Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .github/workflows/acctest-terraform-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,36 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v6
with:
go-version: '1.25'
- run: make tools
- run: make tflint
- name: Run tflint on changed files only
run: |
# Get Go files changed in this PR
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'alicloud/*.go' | grep '\.go$' || true)
if [ -z "$CHANGED" ]; then
echo "No Go files changed, skipping tflint"
exit 0
fi
# Run tflint on entire package, capture output and exit code
TFLINT_EXIT=0
make tflint 2>&1 | tee /tmp/tflint-output.txt || TFLINT_EXIT=$?
if [ "$TFLINT_EXIT" -ne 0 ]; then
# Filter errors to only changed files using full paths
ERRORS=""
for f in $CHANGED; do
MATCH=$(grep -F "$f" /tmp/tflint-output.txt || true)
if [ -n "$MATCH" ]; then
ERRORS="${ERRORS}${MATCH}"$'\n'
fi
done
if [ -n "$ERRORS" ]; then
echo "tflint errors in changed files:"
echo "$ERRORS"
exit 1
fi
fi
echo "No tflint errors in changed files"
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,7 @@ coverage.html
coverage.out

.qwenignore
.terraflow/
.terraflow/

# VCR cassettes (contain API responses, may include account-specific data)
**/testdata/vcr/
2 changes: 1 addition & 1 deletion .opencode/skills/provider-add-attribute/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ make ci-check-quick
make ci-check

# 3. If step 2 has test failures, debug with specific resource and test case:
make test-resource-debug RESOURCE=alicloud_vpc TESTCASE=TestAccAliCloudVPC_enableIpv6 LOGLEVEL=TRACE LOGFILE=vpc-test.log
make acctest RESOURCE=alicloud_vpc TESTCASE=TestAccAliCloudVPC_enableIpv6 LOGLEVEL=TRACE LOGFILE=vpc-test.log
```

## Step 5: Commit Code
Expand Down
4 changes: 2 additions & 2 deletions .opencode/skills/provider-resource-acceptance/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ Execute `provider-resource-review` skill (`load_skills=["provider-resource-revie
Pick a **new** `TestAcc*_basic` test case from this branch. If none, pick simplest existing `_basic`.

```bash
make test-resource-debug RESOURCE=alicloud_<X> TESTCASE=<TestName> LOGLEVEL=TRACE LOGFILE=<X>-test.log
make acctest RESOURCE=alicloud_<X> TESTCASE=<TestName> LOGLEVEL=TRACE LOGFILE=<X>-test.log
```

Fix failures, re-run. Mode A: post errors/fixes to Aone.

## Step 5: Run All Tests

```bash
make test-resource-debug RESOURCE=alicloud_<X>
make acctest RESOURCE=alicloud_<X>
```

For each failure:
Expand Down
50 changes: 44 additions & 6 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,19 @@ goimports: tools
@echo "Done. Processed with up to $(PARALLEL) parallel jobs."

# Test a specific resource with debug logs
# Usage: make test-resource-debug RESOURCE=alicloud_vpc TESTCASE=basic LOGLEVEL=TRACE LOGFILE=vpc-test.log
test-resource-debug:
# Usage:
# make acctest RESOURCE=alicloud_vpc TESTCASE=basic
# make acctest RESOURCE=alicloud_vpc TESTCASE=basic LOGLEVEL=TRACE LOGFILE=vpc-test.log
#
# VCR mode (record/replay API interactions):
# make acctest RESOURCE=alicloud_vpc TESTCASE=basic VCR=record # Record to cassette (needs credentials)
# make acctest RESOURCE=alicloud_vpc TESTCASE=basic VCR=replay # Replay from cassette (no credentials)
# make vcr-list # List available cassettes
# make vcr-clean # Remove all cassettes
VCR_DIR ?= testdata/vcr
acctest:
@if [ -z "$(RESOURCE)" ]; then \
echo "Error: RESOURCE is required. Usage: make test-resource-debug RESOURCE=alicloud_vpc"; \
echo "Error: RESOURCE is required. Usage: make acctest RESOURCE=alicloud_vpc"; \
exit 1; \
fi
@RESOURCE_NAME=$$(echo "$(RESOURCE)" | sed 's/^alicloud_//'); \
Expand All @@ -52,6 +61,7 @@ test-resource-debug:
fi; \
fi; \
echo "Found test file: $$TEST_FILE ($$TEST_TYPE)"; \
VCR_MODE_FLAG="$(VCR)"; \
LOGLEVEL=$${LOGLEVEL:-DEBUG}; \
LOGFILE_BASE="$(LOGFILE)"; \
PROJECT_ROOT=$$(pwd); \
Expand Down Expand Up @@ -95,13 +105,31 @@ test-resource-debug:
FAILED_TESTS=""; \
echo "$$SELECTED_TESTS" | while IFS= read -r TEST_NAME; do \
TEST_NUM=$$((TEST_NUM + 1)); \
VCR_ENV=""; \
if [ -n "$$VCR_MODE_FLAG" ]; then \
VCR_CASSETTE_NAME=$$(echo "$$TEST_NAME" | tr '[:upper:]' '[:lower:]'); \
VCR_CASSETTE="$(VCR_DIR)/$$VCR_CASSETTE_NAME"; \
if [ "$$VCR_MODE_FLAG" = "record" ]; then \
mkdir -p alicloud/$(VCR_DIR); \
VCR_ENV="VCR_MODE=record VCR_PATH=$$VCR_CASSETTE"; \
elif [ "$$VCR_MODE_FLAG" = "replay" ]; then \
if [ ! -f "alicloud/$${VCR_CASSETTE}.yaml" ]; then \
echo "Error: Cassette not found: alicloud/$${VCR_CASSETTE}.yaml"; \
echo "Run 'make acctest RESOURCE=$(RESOURCE) TESTCASE=... VCR=record' first."; \
FAILED_TESTS="$$FAILED_TESTS$$TEST_NAME\n"; \
continue; \
fi; \
VCR_ENV="VCR_MODE=replay VCR_PATH=$$VCR_CASSETTE"; \
fi; \
fi; \
echo "=================================================="; \
echo "[$$TEST_NUM/$$TEST_COUNT] Running: $$TEST_NAME"; \
if [ -n "$$VCR_ENV" ]; then echo " VCR: $$VCR_MODE_FLAG → $$VCR_CASSETTE"; fi; \
echo "=================================================="; \
if [ -n "$$LOGFILE_BASE" ]; then \
TEST_API_LOG="$${PROJECT_ROOT}/$${LOGFILE_BASE}-$${TEST_NAME}-api.log"; \
TEST_CONSOLE_LOG="$${PROJECT_ROOT}/$${LOGFILE_BASE}-$${TEST_NAME}-console.log"; \
if TF_LOG=$$LOGLEVEL TF_LOG_PATH=$$TEST_API_LOG TF_ACC=1 go test -v ./alicloud -run="^$$TEST_NAME\$$" -timeout 360m 2>&1 | tee $$TEST_CONSOLE_LOG; then \
if env $$VCR_ENV TF_LOG=$$LOGLEVEL TF_LOG_PATH=$$TEST_API_LOG TF_ACC=1 go test -v ./alicloud -run="^$$TEST_NAME\$$" -timeout 360m 2>&1 | tee $$TEST_CONSOLE_LOG; then \
echo "✓ PASSED: $$TEST_NAME"; \
echo " API logs: $$TEST_API_LOG"; \
echo " Console logs: $$TEST_CONSOLE_LOG"; \
Expand All @@ -112,7 +140,7 @@ test-resource-debug:
FAILED_TESTS="$$FAILED_TESTS$$TEST_NAME\n"; \
fi; \
else \
if TF_LOG=$$LOGLEVEL TF_ACC=1 go test -v ./alicloud -run="^$$TEST_NAME\$$" -timeout 360m; then \
if env $$VCR_ENV TF_LOG=$$LOGLEVEL TF_ACC=1 go test -v ./alicloud -run="^$$TEST_NAME\$$" -timeout 360m; then \
echo "✓ PASSED: $$TEST_NAME"; \
else \
echo "✗ FAILED: $$TEST_NAME"; \
Expand Down Expand Up @@ -252,7 +280,17 @@ sweep:
TF_ACC=1 go test ./alicloud -v -sweep=$(REGION) -sweep-run=$(RESOURCE); \
fi

.PHONY: build test testacc test-resource test-resource-debug vet fmt fmtcheck errcheck test-compile website website-test commit ci-check ci-check-quick minimal-test-set sweep
# List available VCR cassette files
vcr-list:
@echo "Available cassettes:"
@find alicloud/$(VCR_DIR) -name "*.yaml" 2>/dev/null | sed 's|alicloud/$(VCR_DIR)/||;s|\.yaml$$||' | sort | sed 's/^/ /' || echo " (none)"

# Clean all cassette files
vcr-clean:
@echo "Removing all cassettes in alicloud/$(VCR_DIR)/"
@rm -f alicloud/$(VCR_DIR)/*.yaml

.PHONY: build test testacc acctest vet fmt fmtcheck errcheck test-compile website website-test commit ci-check ci-check-quick minimal-test-set sweep vcr-list vcr-clean

all: mac windows linux

Expand Down
11 changes: 11 additions & 0 deletions alicloud/alicloud_sweeper_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package alicloud

import (
"flag"
"fmt"
"log"
"os"
Expand All @@ -14,6 +15,16 @@ import (
)

func TestMain(m *testing.M) {
if os.Getenv("VCR_PATH") != "" {
// VCR mode: run tests, save cassettes, then exit.
// Cannot use resource.TestMain here because it calls os.Exit
// internally, which would skip the cassette save.
flag.Parse()
exitCode := m.Run()
connectivity.StopVCR()
os.Exit(exitCode)
}
// Default: sweeper support + standard test flow
resource.TestMain(m)
}

Expand Down
13 changes: 12 additions & 1 deletion alicloud/connectivity/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2424,7 +2424,18 @@ func (client *AliyunClient) rpcRequest(method string, apiProductCode string, api
}
}
sdkConfig := client.teaSdkConfig
sdkConfig.SetEndpoint(endpoint)

// VCR: redirect to local proxy, pass original host via query param
if vcrAddr := VCRLocalAddr(); vcrAddr != "" {
if query == nil {
query = make(map[string]interface{})
}
query["__vcr_host"] = endpoint
sdkConfig.SetEndpoint(vcrAddr)
sdkConfig.SetProtocol("HTTP")
} else {
sdkConfig.SetEndpoint(endpoint)
}
credential, err := client.config.Credential.GetCredential()
if err != nil || credential == nil {
return nil, fmt.Errorf("get credential failed. Error: %#v", err)
Expand Down
Loading
Loading