From cf867e953b45cb9d4c65f96b85fb91a0303629dd Mon Sep 17 00:00:00 2001 From: Aleksander Zaruczewski Date: Tue, 27 Feb 2024 21:04:10 +0200 Subject: [PATCH 1/2] test(acctest): incremental run support --- .../incremental-acceptance-tests.yml | 340 ++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 .github/workflows/incremental-acceptance-tests.yml diff --git a/.github/workflows/incremental-acceptance-tests.yml b/.github/workflows/incremental-acceptance-tests.yml new file mode 100644 index 000000000..93ce78241 --- /dev/null +++ b/.github/workflows/incremental-acceptance-tests.yml @@ -0,0 +1,340 @@ +name: Incremental Acceptance Tests + +on: + pull_request: + branches: + - main + - v* + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + push: + branches: + - main + - v* + workflow_dispatch: {} + +permissions: read-all + +concurrency: + group: ci-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + selproj: + name: Run selproj + runs-on: ubuntu-latest + if: > + (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || + github.event_name == 'push' + + outputs: + suffix: ${{ steps.selproj.outputs.suffix }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - id: selproj + run: echo "suffix=$(make -s ci-selproj | tr -d '\n')" >> $GITHUB_OUTPUT + env: + AIVEN_TOKEN: ${{ secrets.AIVEN_TOKEN }} + AIVEN_PROJECT_NAME_PREFIX: ${{ secrets.AIVEN_PROJECT_NAME_PREFIX }} + + find_sdkv2_entities: + name: Find SDKv2 entities + runs-on: ubuntu-latest + if: > + (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || + github.event_name == 'push' + + env: + SDKV2_IMPL_PATH: internal/sdkprovider + + outputs: + entities: ${{ steps.find_entities.outputs.entities }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Find provider.go file + id: find_provider_go_file + run: | + echo "path=$(find "$SDKV2_IMPL_PATH" -type f -name 'provider.go')" >> $GITHUB_OUTPUT + + - name: Extract imports + id: extract_imports + run: | + provider_go_file=${{ steps.find_provider_go_file.outputs.path }} + imports=$(awk '/^import \(/{flag=1;next}/^\)/{flag=0}flag' "$provider_go_file") + imports=$(echo "$imports" | jq -R -s -c 'split("\n") | map(select(length > 0) | gsub("[[:space:]\"]";""))') + echo "imports=$imports" >> $GITHUB_OUTPUT + + - name: Build import map + id: build_import_map + run: | + import_lines=$(echo '${{ steps.extract_imports.outputs.imports }}' | jq -r '.[]') + import_map="{}" + + while IFS= read -r line; do + if [[ $line =~ ^(.*)"$SDKV2_IMPL_PATH"/(.*)$ ]]; then + package_path="${BASH_REMATCH[2]}" + package_name=$(basename "$package_path") + + echo "Found package $package_name in $SDKV2_IMPL_PATH/$package_path" + import_map=$( + echo "$import_map" | jq -c --arg key "$package_name" --arg value "$package_path" \ + '. + {($key): $value}' + ) + fi + done <<< "$import_lines" + + echo "import_map=$import_map" >> $GITHUB_OUTPUT + + - name: Find entities + id: find_entities + run: | + provider_go_file=${{ steps.find_provider_go_file.outputs.path }} + import_map='${{ steps.build_import_map.outputs.import_map }}' + entities="[]" + + while read -r name type func_with_parentheses; do + if [[ -z "$name" || -z "$func_with_parentheses" ]]; then + continue + fi + + func="${func_with_parentheses%)*}" + func="${func##*.}" + package_name="${func_with_parentheses%%.*}" + path=$(echo $import_map | jq -r --arg package_name "$package_name" '.[$package_name] // empty') + + if [[ -n "$path" ]]; then + path="$SDKV2_IMPL_PATH/$path" + file=$(find "$path" -type f -name '*.go' -exec grep -l "$func" {} +) + + if [[ -n "$file" ]]; then + echo "Found $type $name in $file" + entities=$( + echo "$entities" | jq -c --arg name "$name" --arg type "$type" --arg file "$file" \ + '. + [{($name): {("type"): $type, ("file"): $file}}]' + ) + fi + fi + done < <(awk -v file="$provider_go_file" ' + /ResourcesMap: map\[string\]\*schema\.Resource{/ { type="resource"; capture = 1; next } + /DataSourcesMap: map\[string\]\*schema\.Resource{/ { type="datasource"; capture = 1; next } + capture && /\}/ { capture = 0 } + capture && NF { + gsub(/[\t "]+/, "") + split($0, a, ":") + print a[1], type, a[2] + } + ' "$provider_go_file") + + echo "entities=$entities" >> $GITHUB_OUTPUT + + find_plugin_framework_entities: + name: Find Plugin Framework entities + runs-on: ubuntu-latest + if: > + (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip workflows')) || + github.event_name == 'push' + + env: + PLUGIN_FRAMEWORK_IMPL_PATH: internal/plugin + + outputs: + entities: ${{ steps.find_entities.outputs.entities }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Find entities + id: find_entities + run: | + entities="[]" + + while IFS= read -r file; do + while IFS=, read -r name type file; do + echo "Found $type $name in $file" + entities=$( + echo "$entities" | jq -c --arg name "$name" --arg type "$type" --arg file "$file" \ + '. + [{($name): {("type"): $type, ("file"): $file}}]' + ) + done < <(awk -v file="$file" ' + /resp\.TypeName\s*=\s*req\.ProviderTypeName\s*\+\s*"/ { + match($0, /"(_[^"]+)"/, arr) + if (length(arr[1]) > 0) { + type = "datasource" + while((getline line < file) > 0) { + if (line ~ /_ resource\.Resource/) { + type = "resource" + break + } + } + close(file) + print "aiven" arr[1] "," type "," file + } + } + ' "$file") + done < <(find "$PLUGIN_FRAMEWORK_IMPL_PATH" -type f -name '*.go') + + echo "entities=$entities" >> $GITHUB_OUTPUT + + combine_entities: + name: Combine entities + runs-on: ubuntu-latest + + needs: + - find_sdkv2_entities + - find_plugin_framework_entities + + outputs: + entities: ${{ steps.combine_entities.outputs.entities }} + + steps: + - name: Combine entities + id: combine_entities + run: | + entities='[]' + + mapfile -t sdkv2_entities < <(echo '${{ needs.find_sdkv2_entities.outputs.entities }}' | jq -c '.[]') + mapfile -t plugin_framework_entities < <( + echo '${{ needs.find_plugin_framework_entities.outputs.entities }}' | jq -c '.[]' + ) + + add_entity_to_entities() { + local entity_json=$1 + entities=$( + jq -c --argjson entities "$entities" --argjson entity_json "$entity_json" \ + '$entities + [($entity_json | to_entries | .[0] | {key: .key, value: .value}) | {(.key): .value}]' \ + <<< "{}" + ) + } + + for entity_json in "${sdkv2_entities[@]}" "${plugin_framework_entities[@]}"; do + add_entity_to_entities "$entity_json" + done + + echo "entities=$entities" >> $GITHUB_OUTPUT + + find_tests: + name: Find tests + runs-on: ubuntu-latest + + needs: + - combine_entities + + outputs: + tests: ${{ steps.find_tests.outputs.tests }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Find tests + id: find_tests + run: | + tests=() + + mapfile -t found_entities < <(echo '${{ needs.combine_entities.outputs.entities }}' | jq -c '.[]') + + for found_entity in "${found_entities[@]}"; do + name=$(echo "$found_entity" | jq -r 'keys[0]') + type=$(echo "$found_entity" | jq -r --arg name "$name" '.[$name].type') + file=$(echo "$found_entity" | jq -r --arg name "$name" '.[$name].file') + dir=$(dirname "$file") + + file_changed=false + dep_changed=false + + if git diff "origin/${{ github.base_ref || 'main' }}" --name-only | grep -q "^$file$"; then + echo "Definition of $name $type in $file changed" + file_changed=true + else + deps=$( + go list -json "./$dir" | jq -r '.Deps[]' | grep -oP '^github.com/aiven/terraform-provider-aiven/\K.*' + ) + for dep in $deps; do + if git diff "origin/${{ github.base_ref || 'main' }}" --name-only | grep -q "$dep"; then + echo "Dependency $dep of $name $type changed" + dep_changed=true + break + fi + done + fi + + if [ "$file_changed" = true ] || [ "$dep_changed" = true ]; then + pattern="" + + [[ "$type" == "resource" ]] && pattern="resource \"$name\"" + [[ "$type" == "datasource" ]] && pattern="data \"$name\"" + + while IFS= read -r test_file; do + if grep -q "$pattern" "$test_file"; then + echo "Found test for $name $type in $test_file" + tests+=("$test_file") + fi + done < <(find internal -type f -name '*_test.go' -exec grep -l "$pattern" {} +) + fi + done + + readarray -t unique_tests < <(printf '%s\n' "${tests[@]}" | awk '!seen[$0]++') + tests_json=$(printf '%s\n' "${unique_tests[@]}" | jq -R . | jq -s -c .) + + echo "tests=$tests_json" >> $GITHUB_OUTPUT + + run_tests: + name: Run tests + runs-on: ubuntu-latest + + needs: + - selproj + - find_tests + + env: + COUNT: 1 + PARALLEL: 10 + TIMEOUT: 180m + + strategy: + max-parallel: 5 + matrix: + test: ${{ fromJson(needs.find_tests.outputs.tests) }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Run tests + run: go test ${{ matrix.test }} -v -count $COUNT -parallel $PARALLEL -timeout $TIMEOUT + env: + TF_ACC: 1 + CGO_ENABLED: 0 + AIVEN_TOKEN: ${{ secrets.AIVEN_TOKEN }} + AIVEN_PROJECT_NAME: ${{ secrets.AIVEN_PROJECT_NAME_PREFIX }}${{ needs.selproj.outputs.suffix }} + AIVEN_ORGANIZATION_NAME: ${{ secrets.AIVEN_ORGANIZATION_NAME }} + AIVEN_ACCOUNT_NAME: ${{ secrets.AIVEN_ORGANIZATION_NAME }} From 7bf752b2fe02f9dbdb2e985734105db27e592db8 Mon Sep 17 00:00:00 2001 From: Jeffrey Held Date: Tue, 5 Mar 2024 09:53:38 +0100 Subject: [PATCH 2/2] test: checking things --- internal/sdkprovider/service/pg/pg.go | 2 +- internal/sdkprovider/service/redis/redis_test.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/sdkprovider/service/pg/pg.go b/internal/sdkprovider/service/pg/pg.go index a6d85cd19..97e3e1b95 100644 --- a/internal/sdkprovider/service/pg/pg.go +++ b/internal/sdkprovider/service/pg/pg.go @@ -168,7 +168,7 @@ func resourceServicePGUpdate(ctx context.Context, d *schema.ResourceData, m inte task := taskI.(*aiven.ServiceTaskResponse) if !*task.Task.Success { return diag.Errorf( - "PG service upgrade check error, version upgrade from %s to %s, result: %s", + "PG service upgrade task failed when checking version upgrade from %s to %s, result: %s", task.Task.SourcePgVersion, task.Task.TargetPgVersion, task.Task.Result) } diff --git a/internal/sdkprovider/service/redis/redis_test.go b/internal/sdkprovider/service/redis/redis_test.go index 7fd652ab7..71b6d1102 100644 --- a/internal/sdkprovider/service/redis/redis_test.go +++ b/internal/sdkprovider/service/redis/redis_test.go @@ -74,7 +74,7 @@ data "aiven_project" "foo" { resource "aiven_redis" "bar" { project = data.aiven_project.foo.project cloud_name = "google-europe-west1" - plan = "startup-4" + plan = "hobbyist" service_name = "test-acc-sr-%s" maintenance_window_dow = "monday" maintenance_window_time = "10:00:00" @@ -114,7 +114,7 @@ data "aiven_project" "foo" { resource "aiven_redis" "bar" { project = data.aiven_project.foo.project cloud_name = "google-europe-west1" - plan = "startup-4" + plan = "hobbyist" service_name = "test-acc-sr-%s" maintenance_window_dow = "monday" maintenance_window_time = "10:00:00" @@ -150,7 +150,7 @@ data "aiven_project" "foo" { resource "aiven_redis" "bar" { project = data.aiven_project.foo.project cloud_name = "google-europe-west1" - plan = "startup-4" + plan = "hobbyist" service_name = "test-acc-sr-%s" maintenance_window_dow = "monday" maintenance_window_time = "10:00:00" @@ -234,7 +234,7 @@ data "aiven_project" "foo" { resource "aiven_redis" "bar" { project = data.aiven_project.foo.project cloud_name = "google-europe-west1" - plan = "startup-4" + plan = "hobbyist" service_name = "test-acc-sr-%s" maintenance_window_dow = "monday" maintenance_window_time = "10:00:00" @@ -265,7 +265,7 @@ data "aiven_project" "foo" { resource "aiven_redis" "bar" { project = data.aiven_project.foo.project cloud_name = "google-europe-west1" - plan = "startup-4" + plan = "hobbyist" service_name = "test-acc-sr-%s" maintenance_window_dow = "monday" maintenance_window_time = "10:00:00"