diff --git a/Makefile b/Makefile index 15b7ecf13f..35c593d1e1 100644 --- a/Makefile +++ b/Makefile @@ -30,8 +30,10 @@ KIND_NAME ?= apisix-ingress-cluster GATEAY_API_VERSION ?= v1.2.0 ADC_VERSION ?= 0.20.0 +GINKGO_VERSION ?= 2.20.0 TEST_TIMEOUT ?= 80m TEST_DIR ?= ./test/e2e/apisix/ +E2E_NODES ?= 2 # CRD Reference Documentation CRD_REF_DOCS_VERSION ?= v0.1.0 @@ -127,6 +129,14 @@ kind-e2e-test: kind-up build-image kind-load-images e2e-test e2e-test: go test $(TEST_DIR) -test.timeout=$(TEST_TIMEOUT) -v -ginkgo.v -ginkgo.focus="$(TEST_FOCUS)" -ginkgo.label-filter="$(TEST_LABEL)" +.PHONY: ginkgo-e2e-test +ginkgo-e2e-test: + @ginkgo -cover -coverprofile=coverage.txt -r --randomize-all --randomize-suites --trace --focus=$(E2E_FOCUS) --nodes=$(E2E_NODES) $(TEST_DIR) + +.PHONY: install-ginkgo +install-ginkgo: + @go install github.com/onsi/ginkgo/v2/ginkgo@v$(GINKGO_VERSION) + .PHONY: conformance-test conformance-test: go test -v ./test/conformance -tags=conformance -timeout 60m diff --git a/go.mod b/go.mod index 068e83a91a..3e5cf55607 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/go-logr/logr v1.4.2 github.com/go-logr/zapr v1.3.0 github.com/google/uuid v1.6.0 - github.com/gruntwork-io/terratest v0.47.0 + github.com/gruntwork-io/terratest v0.50.0 github.com/hashicorp/go-memdb v1.3.4 github.com/incubator4/go-resty-expr v0.1.1 github.com/onsi/ginkgo/v2 v2.20.0 @@ -19,7 +19,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/samber/lo v1.47.0 github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 gopkg.in/yaml.v3 v3.0.1 @@ -35,6 +35,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect @@ -42,13 +43,48 @@ require ( github.com/andybalholm/brotli v1.0.4 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.44.245 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.5 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect + github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 // indirect + github.com/aws/aws-sdk-go-v2/service/acm v1.30.6 // indirect + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.0 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.44.0 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.37.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.37.6 // indirect + github.com/aws/aws-sdk-go-v2/service/lambda v1.69.0 // indirect + github.com/aws/aws-sdk-go-v2/service/rds v1.91.0 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 // indirect + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sns v1.33.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sqs v1.37.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.56.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect + github.com/aws/smithy-go v1.22.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect @@ -63,7 +99,7 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -88,6 +124,10 @@ require ( github.com/imdario/mergo v0.3.16 // indirect github.com/imkira/go-interpol v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -107,7 +147,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pquerna/otp v1.2.0 // indirect + github.com/pquerna/otp v1.4.0 // indirect github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -119,7 +159,7 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - github.com/urfave/cli v1.22.14 // indirect + github.com/urfave/cli v1.22.16 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.34.0 // indirect github.com/x448/float16 v0.8.4 // indirect @@ -129,31 +169,31 @@ require ( github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/sdk v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.6.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect golang.org/x/text v0.23.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.24.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.66.2 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index 2be83ffae3..9ba0327403 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -22,8 +24,78 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.44.245 h1:KtY2s4q31/kn33AdV63R5t77mdxsI7rq3YT7Mgo805M= -github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= +github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc= +github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0= +github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41 h1:hqcxMc2g/MwwnRMod9n6Bd+t+9Nf7d5qRg7RaXKPd6o= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41/go.mod h1:d1eH0VrttvPmrCraU68LOyNdu26zFxQFjrVSb5vdhog= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 h1:JX70yGKLj25+lMC5Yyh8wBtvB01GDilyRuJvXJ4piD0= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24/go.mod h1:+Ln60j9SUTD0LEwnhEB0Xhg61DHqplBrbZpLgyjoEHg= +github.com/aws/aws-sdk-go-v2/service/acm v1.30.6 h1:fDg0RlN30Xf/yYzEUL/WXqhmgFsjVb/I3230oCfyI5w= +github.com/aws/aws-sdk-go-v2/service/acm v1.30.6/go.mod h1:zRR6jE3v/TcbfO8C2P+H0Z+kShiKKVaVyoIl8NQRjyg= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.0 h1:1KzQVZi7OTixxaVJ8fWaJAUBjme+iQ3zBOCZhE4RgxQ= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.51.0/go.mod h1:I1+/2m+IhnK5qEbhS3CrzjeiVloo9sItE/2K+so0fkU= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.44.0 h1:OREVd94+oXW5a+3SSUAo4K0L5ci8cucCLu+PSiek8OU= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.44.0/go.mod h1:Qbr4yfpNqVNl69l/GEDK+8wxLf/vHi0ChoiSDzD7thU= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.37.1 h1:vucMirlM6D+RDU8ncKaSZ/5dGrXNajozVwpmWNPn2gQ= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.37.1/go.mod h1:fceORfs010mNxZbQhfqUjUeHlTwANmIT4mvHamuUaUg= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0 h1:RhSoBFT5/8tTmIseJUXM6INTXTQDF8+0oyxWBnozIms= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.193.0/go.mod h1:mzj8EEjIHSN2oZRXiw1Dd+uB4HZTl7hC8nBzX9IZMWw= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6 h1:zg+3FGHA0PBs0KM25qE/rOf2o5zsjNa1g/Qq83+SDI0= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6/go.mod h1:ZSq54Z9SIsOTf1Efwgw1msilSs4XVEfVQiP9nYVnKpM= +github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0 h1:7/vgFWplkusJN/m+3QOa+W9FNRqa8ujMPNmdufRaJpg= +github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0/go.mod h1:dPTOvmjJQ1T7Q+2+Xs2KSPrMvx+p0rpyV+HsQVnUK4o= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 h1:hfkzDZHBp9jAT4zcd5mtqckpU4E3Ax0LQaEWWk1VgN8= +github.com/aws/aws-sdk-go-v2/service/iam v1.38.1/go.mod h1:u36ahDtZcQHGmVm/r+0L1sfKX4fzLEMdCqiKRKkUMVM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 h1:gvZOjQKPxFXy1ft3QnEyXmT+IqneM9QAUWlM3r0mfqw= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5/go.mod h1:DLWnfvIcm9IET/mmjdxeXbBKmTCm0ZB8p1za9BVteM8= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.5 h1:3Y457U2eGukmjYjeHG6kanZpDzJADa2m0ADqnuePYVQ= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.5/go.mod h1:CfwEHGkTjYZpkQ/5PvcbEtT7AJlG68KkEvmtwU8z3/U= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 h1:P1doBzv5VEg1ONxnJss1Kh5ZG/ewoIE4MQtKKc6Crgg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5/go.mod h1:NOP+euMW7W3Ukt28tAxPuoWao4rhhqJD3QEBk7oCg7w= +github.com/aws/aws-sdk-go-v2/service/kms v1.37.6 h1:CZImQdb1QbU9sGgJ9IswhVkxAcjkkD1eQTMA1KHWk+E= +github.com/aws/aws-sdk-go-v2/service/kms v1.37.6/go.mod h1:YJDdlK0zsyxVBxGU48AR/Mi8DMrGdc1E3Yij4fNrONA= +github.com/aws/aws-sdk-go-v2/service/lambda v1.69.0 h1:BXt75frE/FYtAmEDBJRBa2HexOw+oAZWZl6QknZEFgg= +github.com/aws/aws-sdk-go-v2/service/lambda v1.69.0/go.mod h1:guz2K3x4FKSdDaoeB+TPVgJNU9oj2gftbp5cR8ela1A= +github.com/aws/aws-sdk-go-v2/service/rds v1.91.0 h1:eqHz3Uih+gb0vLE5Cc4Xf733vOxsxDp6GFUUVQU4d7w= +github.com/aws/aws-sdk-go-v2/service/rds v1.91.0/go.mod h1:h2jc7IleH3xHY7y+h8FH7WAZcz3IVLOB6/jXotIQ/qU= +github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2 h1:wmt05tPp/CaRZpPV5B4SaJ5TwkHKom07/BzHoLdkY1o= +github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2/go.mod h1:d+K9HESMpGb1EU9/UmmpInbGIUcAkwmcY6ZO/A3zZsw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 h1:Q2ax8S21clKOnHhhr933xm3JxdJebql+R7aNo7p7GBQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0/go.mod h1:ralv4XawHjEMaHOWnTFushl0WRqim/gQWesAMF6hTow= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6 h1:1KDMKvOKNrpD667ORbZ/+4OgvUoaok1gg/MLzrHF9fw= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6/go.mod h1:DmtyfCfONhOyVAJ6ZMTrDSFIeyCBlEO93Qkfhxwbxu0= +github.com/aws/aws-sdk-go-v2/service/sns v1.33.6 h1:lEUtRHICiXsd7VRwRjXaY7MApT2X4Ue0Mrwe6XbyBro= +github.com/aws/aws-sdk-go-v2/service/sns v1.33.6/go.mod h1:SODr0Lu3lFdT0SGsGX1TzFTapwveBrT5wztVoYtppm8= +github.com/aws/aws-sdk-go-v2/service/sqs v1.37.1 h1:39WvSrVq9DD6UHkD+fx5x19P5KpRQfNdtgReDVNbelc= +github.com/aws/aws-sdk-go-v2/service/sqs v1.37.1/go.mod h1:3gwPzC9LER/BTQdQZ3r6dUktb1rSjABF1D3Sr6nS7VU= +github.com/aws/aws-sdk-go-v2/service/ssm v1.56.0 h1:mADKqoZaodipGgiZfuAjtlcr4IVBtXPZKVjkzUZCCYM= +github.com/aws/aws-sdk-go-v2/service/ssm v1.56.0/go.mod h1:l9qF25TzH95FhcIak6e4vt79KE4I7M2Nf59eMUVjj6c= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -38,9 +110,9 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -90,8 +162,8 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -130,8 +202,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro= github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78= -github.com/gruntwork-io/terratest v0.47.0 h1:xIy1pT7NbGVlMLDZEHl3+3iSnvffh8tN2pL6idn448c= -github.com/gruntwork-io/terratest v0.47.0/go.mod h1:oywHw1cFKXSYvKPm27U7quZVzDUlA22H2xUrKCe26xM= +github.com/gruntwork-io/terratest v0.50.0 h1:AbBJ7IRCpLZ9H4HBrjeoWESITv8nLjN6/f1riMNcAsw= +github.com/gruntwork-io/terratest v0.50.0/go.mod h1:see0lbKvAqz6rvzvN2wyfuFQQG4PWcAb2yHulF6B2q4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -165,6 +237,14 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/incubator4/go-resty-expr v0.1.1 h1:9ur1M+p0wDzL1bprdGzHugGkfK0Yd3Ba/ijcgvL+a1k= github.com/incubator4/go-resty-expr v0.1.1/go.mod h1:w9YQkQLUs1cArOb4O7SGJwJL/L8kuAo6y5CVS2o9eag= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -243,8 +323,8 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= -github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= +github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -288,6 +368,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -298,14 +379,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= -github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= +github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4= @@ -331,20 +413,20 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -385,12 +467,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -413,14 +494,12 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= @@ -431,8 +510,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -448,16 +527,16 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/test/e2e/apisix/e2e_test.go b/test/e2e/apisix/e2e_test.go index da357c5d8e..ea814157eb 100644 --- a/test/e2e/apisix/e2e_test.go +++ b/test/e2e/apisix/e2e_test.go @@ -38,9 +38,7 @@ func TestAPISIXE2E(t *testing.T) { _ = framework.NewFramework() // init newDeployer function - scaffold.NewDeployer = func(s *scaffold.Scaffold) scaffold.Deployer { - return scaffold.NewAPISIXDeployer(s) - } + scaffold.NewDeployer = scaffold.NewAPISIXDeployer _, _ = fmt.Fprintf(GinkgoWriter, "Starting APISIX standalone e2e suite\n") RunSpecs(t, "apisix standalone e2e suite") diff --git a/test/e2e/apisix/status.go b/test/e2e/apisix/status.go index 1c72e4128a..7bc0b6a538 100644 --- a/test/e2e/apisix/status.go +++ b/test/e2e/apisix/status.go @@ -39,10 +39,6 @@ var _ = Describe("Test CRD Status", Label("apisix.apache.org", "v2", "apisixrout applier = framework.NewApplier(s.GinkgoT, s.K8sClient, s.CreateResourceFromString) ) - assertion := func(actualOrCtx any, args ...any) AsyncAssertion { - return Eventually(actualOrCtx).WithArguments(args...).WithTimeout(30 * time.Second).ProbeEvery(time.Second) - } - Context("Test ApisixRoute Sync Status", func() { BeforeEach(func() { By("create GatewayProxy") @@ -95,22 +91,16 @@ spec: - name: non-existent-plugin enable: true ` - - getRequest := func(path string) func() int { - return func() int { - return s.NewAPISIXClient().GET(path).WithHost("httpbin").Expect().Raw().StatusCode - } - } - It("unknown plugin", func() { if os.Getenv("PROVIDER_TYPE") == "apisix-standalone" { Skip("apisix standalone does not validate unknown plugins") } By("apply ApisixRoute with valid plugin") - applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "default"}, &apiv2.ApisixRoute{}, arWithInvalidPlugin) + err := s.CreateResourceFromString(arWithInvalidPlugin) + Expect(err).NotTo(HaveOccurred(), "creating ApisixRoute with valid plugin") By("check ApisixRoute status") - assertion(func() string { + s.RetryAssertion(func() string { output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml") return output }).Should( @@ -124,67 +114,62 @@ spec: By("Update ApisixRoute") applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "default"}, &apiv2.ApisixRoute{}, ar) - By("check ApisixRoute status") - assertion(func() string { - output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml") - return output - }).Should( - And( - ContainSubstring(`status: "True"`), - ContainSubstring(`reason: Accepted`), - ), - ) - By("check route in APISIX") - assertion(getRequest("/get")).Should(Equal(200), "should be able to access the route") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin", + Check: scaffold.WithExpectedStatus(200), + }) }) It("dataplane unavailable", func() { By("apply ApisixRoute") applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "default"}, &apiv2.ApisixRoute{}, ar) - By("check ApisixRoute status") - assertion(func() string { - output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml") - return output - }).Should( - And( - ContainSubstring(`status: "True"`), - ContainSubstring(`reason: Accepted`), - ), - ) - By("check route in APISIX") - assertion(getRequest("/get")).Should(Equal(200), "should be able to access the route") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Headers: map[string]string{"Host": "httpbin"}, + Check: scaffold.WithExpectedStatus(200), + }) s.Deployer.ScaleDataplane(0) By("check ApisixRoute status") - assertion(func() string { + s.RetryAssertion(func() string { output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml") return output - }).Should( - And( - ContainSubstring(`status: "False"`), - ContainSubstring(`reason: SyncFailed`), - ), - ) + }).WithTimeout(80 * time.Second). + Should( + And( + ContainSubstring(`status: "False"`), + ContainSubstring(`reason: SyncFailed`), + ), + ) s.Deployer.ScaleDataplane(1) By("check ApisixRoute status after scaling up") - assertion(func() string { + s.RetryAssertion(func() string { output, _ := s.GetOutputFromString("ar", "default", "-o", "yaml") return output - }).Should( - And( - ContainSubstring(`status: "True"`), - ContainSubstring(`reason: Accepted`), - ), - ) + }).WithTimeout(80 * time.Second). + Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring(`reason: Accepted`), + ), + ) By("check route in APISIX") - assertion(getRequest("/get")).Should(Equal(200), "should be able to access the route") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin", + Check: scaffold.WithExpectedStatus(200), + }) }) }) @@ -276,67 +261,55 @@ spec: AfterEach(func() { _ = s.DeleteResource("Gateway", "apisix") }) - getRequest := func(path string) func() int { - return func() int { - return s.NewAPISIXClient().GET(path).WithHost("httpbin").Expect().Raw().StatusCode - } - } - var resourceApplied = func(resourType, resourceName, resourceRaw string, observedGeneration int) { - Expect(s.CreateResourceFromString(resourceRaw)). - NotTo(HaveOccurred(), fmt.Sprintf("creating %s", resourType)) - - Eventually(func() string { - hryaml, err := s.GetResourceYaml(resourType, resourceName) - Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("getting %s yaml", resourType)) - return hryaml - }, "8s", "2s"). - Should( - SatisfyAll( - ContainSubstring(`status: "True"`), - ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), - ), - fmt.Sprintf("checking %s condition status", resourType), - ) - time.Sleep(5 * time.Second) - } It("dataplane unavailable", func() { By("Create HTTPRoute") - resourceApplied("HTTPRoute", "httpbin", httproute, 1) + err := s.CreateResourceFromString(httproute) + Expect(err).NotTo(HaveOccurred(), "creating HTTPRoute") By("check route in APISIX") - assertion(getRequest("/get")).Should(Equal(200), "should be able to access the route") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin", + Check: scaffold.WithExpectedStatus(200), + }) s.Deployer.ScaleDataplane(0) - time.Sleep(10 * time.Second) By("check ApisixRoute status") - assertion(func() string { + s.RetryAssertion(func() string { output, _ := s.GetOutputFromString("httproute", "httpbin", "-o", "yaml") return output - }).Should( - And( - ContainSubstring(`status: "False"`), - ContainSubstring(`reason: SyncFailed`), - ), - ) + }).WithTimeout(80 * time.Second). + Should( + And( + ContainSubstring(`status: "False"`), + ContainSubstring(`reason: SyncFailed`), + ), + ) s.Deployer.ScaleDataplane(1) - time.Sleep(10 * time.Second) By("check ApisixRoute status after scaling up") - assertion(func() string { + s.RetryAssertion(func() string { output, _ := s.GetOutputFromString("httproute", "httpbin", "-o", "yaml") return output - }).Should( - And( - ContainSubstring(`status: "True"`), - ContainSubstring(`reason: Accepted`), - ), - ) + }).WithTimeout(80 * time.Second). + Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring(`reason: Accepted`), + ), + ) By("check route in APISIX") - assertion(getRequest("/get")).Should(Equal(200), "should be able to access the route") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin", + Check: scaffold.WithExpectedStatus(200), + }) }) }) }) diff --git a/test/e2e/crds/backendtrafficpolicy.go b/test/e2e/crds/backendtrafficpolicy.go index 4dc2ca9227..82b88a201d 100644 --- a/test/e2e/crds/backendtrafficpolicy.go +++ b/test/e2e/crds/backendtrafficpolicy.go @@ -19,7 +19,6 @@ package gatewayapi import ( "fmt" - "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -130,33 +129,55 @@ spec: }) It("should rewrite upstream host", func() { s.ResourceApplied("BackendTrafficPolicy", "httpbin", createUpstreamHost, 1) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body().Contains("httpbin.example.com") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.org", + Headers: map[string]string{ + "Host": "httpbin.org", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains( + "httpbin.example.com", + ), + }, + }) s.ResourceApplied("BackendTrafficPolicy", "httpbin", updateUpstreamHost, 2) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body().Contains("httpbin.update.example.com") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.org", + Headers: map[string]string{ + "Host": "httpbin.org", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains( + "httpbin.update.example.com", + ), + }, + }) err := s.DeleteResourceFromString(createUpstreamHost) Expect(err).NotTo(HaveOccurred(), "deleting BackendTrafficPolicy") - time.Sleep(5 * time.Second) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body(). - NotContains("httpbin.update.example.com"). - NotContains("httpbin.example.com") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.org", + Headers: map[string]string{ + "Host": "httpbin.org", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyNotContains( + "httpbin.update.example.com", + "httpbin.example.com", + ), + }, + }) }) }) }) @@ -231,7 +252,6 @@ spec: By("create Ingress with GatewayProxy IngressClass") err = s.CreateResourceFromString(defaultIngress) Expect(err).NotTo(HaveOccurred(), "creating Ingress with GatewayProxy IngressClass") - time.Sleep(5 * time.Second) } Context("Rewrite Upstream Host", func() { @@ -265,34 +285,36 @@ spec: BeforeEach(beforeEach) It("should rewrite upstream host", func() { + reqAssert := &scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.org", + Headers: map[string]string{ + "Host": "httpbin.org", + }, + } s.ResourceApplied("BackendTrafficPolicy", "httpbin", createUpstreamHost, 1) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body().Contains("httpbin.example.com") + s.RequestAssert(reqAssert.SetChecks( + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("httpbin.example.com"), + )) s.ResourceApplied("BackendTrafficPolicy", "httpbin", updateUpstreamHost, 2) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body().Contains("httpbin.update.example.com") + s.RequestAssert(reqAssert.SetChecks( + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyContains("httpbin.update.example.com"), + )) err := s.DeleteResourceFromString(createUpstreamHost) Expect(err).NotTo(HaveOccurred(), "deleting BackendTrafficPolicy") - time.Sleep(5 * time.Second) - s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.org"). - Expect(). - Status(200). - Body(). - NotContains("httpbin.update.example.com"). - NotContains("httpbin.example.com") + s.RequestAssert(reqAssert.SetChecks( + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedBodyNotContains( + "httpbin.update.example.com", + "httpbin.example.com", + ), + )) }) }) }) diff --git a/test/e2e/crds/consumer.go b/test/e2e/crds/consumer.go index 879d604895..26b8554f51 100644 --- a/test/e2e/crds/consumer.go +++ b/test/e2e/crds/consumer.go @@ -19,8 +19,6 @@ package gatewayapi import ( "fmt" - "net/http" - "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -161,35 +159,47 @@ spec: s.ResourceApplied("Consumer", "consumer-sample", limitCountConsumer, 1) s.ResourceApplied("Consumer", "consumer-sample2", unlimitConsumer, 1) - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(200), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(200), + }) By("trigger limit-count") - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(503) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(503), + }) for i := 0; i < 10; i++ { - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key2"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key2", + }, + Check: scaffold.WithExpectedStatus(200), + }) } }) }) @@ -244,72 +254,98 @@ spec: It("Create/Update/Delete", func() { s.ResourceApplied("Consumer", "consumer-sample", defaultCredential, 1) - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key2"). - WithHost("httpbin.org"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(200), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key2", + }, + Check: scaffold.WithExpectedStatus(200), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(200), + }) By("update Consumer") s.ResourceApplied("Consumer", "consumer-sample", updateCredential, 2) - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(401) - - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key2"). - WithHost("httpbin.org"). - Expect(). - Status(401) - - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "consumer-key"). - WithHost("httpbin.org"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(401), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key2", + }, + Check: scaffold.WithExpectedStatus(401), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "consumer-key", + }, + Check: scaffold.WithExpectedStatus(200), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(200), + }) By("delete Consumer") err := s.DeleteResourceFromString(updateCredential) Expect(err).NotTo(HaveOccurred(), "deleting Consumer") - time.Sleep(5 * time.Second) - - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(401) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(401), + }) }) - }) + }) Context("SecretRef", func() { var keyAuthSecret = ` apiVersion: v1 @@ -370,61 +406,79 @@ spec: Expect(err).NotTo(HaveOccurred(), "creating basic-auth secret") s.ResourceApplied("Consumer", "consumer-sample", defaultConsumer, 1) - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(200), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(200), + }) // update basic-auth password err = s.CreateResourceFromString(basicAuthSecret2) Expect(err).NotTo(HaveOccurred(), "creating basic-auth secret") // use the old password will get 401 - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second). - Should(Equal(http.StatusUnauthorized)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(401), + }) // use the new password will get 200 - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password-new"). - WithHost("httpbin.org"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password-new", + }, + Check: scaffold.WithExpectedStatus(200), + }) By("delete consumer") err = s.DeleteResourceFromString(defaultConsumer) Expect(err).NotTo(HaveOccurred(), "deleting consumer") - time.Sleep(5 * time.Second) - - s.NewAPISIXClient(). - GET("/get"). - WithHeader("apikey", "sample-key"). - WithHost("httpbin.org"). - Expect(). - Status(401) - - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(401) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + Headers: map[string]string{ + "apikey": "sample-key", + }, + Check: scaffold.WithExpectedStatus(401), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(401), + }) }) }) @@ -471,12 +525,16 @@ spec: s.ResourceApplied("Consumer", "consumer-sample", defaultCredential, 1) // verify basic-auth works - s.NewAPISIXClient(). - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(200), + }) By("create additional gateway group to get new admin key") var err error @@ -490,26 +548,35 @@ spec: Expect(err).NotTo(HaveOccurred(), "creating APISIX client for additional gateway group") By("Consumer not found for additional gateway group") - client. - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(404), + }) By("update GatewayProxy with new admin key") updatedProxy := fmt.Sprintf(updatedGatewayProxy, s.Deployer.GetAdminEndpoint(resources.DataplaneService), resources.AdminAPIKey) err = s.CreateResourceFromString(updatedProxy) Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") - time.Sleep(5 * time.Second) By("verify Consumer works for additional gateway group") - client. - GET("/get"). - WithBasicAuth("sample-user", "sample-password"). - WithHost("httpbin.org"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin.org", + BasicAuth: &scaffold.BasicAuth{ + Username: "sample-user", + Password: "sample-password", + }, + Check: scaffold.WithExpectedStatus(200), + }) }) }) }) diff --git a/test/e2e/framework/manifests/apisix.yaml b/test/e2e/framework/manifests/apisix.yaml index affa4bfb57..6b4adbbc8f 100644 --- a/test/e2e/framework/manifests/apisix.yaml +++ b/test/e2e/framework/manifests/apisix.yaml @@ -93,6 +93,13 @@ spec: volumeMounts: - name: config-writable mountPath: /usr/local/apisix/conf + readinessProbe: + failureThreshold: 6 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + tcpSocket: + port: 9080 volumes: - name: config-source configMap: diff --git a/test/e2e/framework/manifests/ingress.yaml b/test/e2e/framework/manifests/ingress.yaml index c4bb101470..addb9552ef 100644 --- a/test/e2e/framework/manifests/ingress.yaml +++ b/test/e2e/framework/manifests/ingress.yaml @@ -68,7 +68,7 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: apisix-ingress-manager-role + name: {{ .Namespace }}-apisix-ingress-manager-role rules: - apiGroups: - "" @@ -244,7 +244,7 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: apisix-ingress-metrics-auth-role + name: {{ .Namespace }}-apisix-ingress-metrics-auth-role rules: - apiGroups: - authentication.k8s.io @@ -262,7 +262,7 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: apisix-ingress-metrics-reader + name: {{ .Namespace }}-apisix-ingress-metrics-reader rules: - nonResourceURLs: - /metrics @@ -280,7 +280,7 @@ metadata: roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: apisix-ingress-leader-election-role + name: {{ .Namespace }}-apisix-ingress-leader-election-role subjects: - kind: ServiceAccount name: apisix-ingress-controller-manager @@ -292,11 +292,11 @@ metadata: labels: app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: apisix-ingress - name: apisix-ingress-manager-rolebinding + name: {{ .Namespace }}-apisix-ingress-manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: apisix-ingress-manager-role + name: {{ .Namespace }}-apisix-ingress-manager-role subjects: - kind: ServiceAccount name: apisix-ingress-controller-manager @@ -305,11 +305,11 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: apisix-ingress-metrics-auth-rolebinding + name: {{ .Namespace }}-apisix-ingress-metrics-auth-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: apisix-ingress-metrics-auth-role + name: {{ .Namespace }}-apisix-ingress-metrics-auth-role subjects: - kind: ServiceAccount name: apisix-ingress-controller-manager @@ -320,14 +320,13 @@ apiVersion: v1 kind: ConfigMap metadata: name: ingress-config + namespace: {{ .Namespace }} data: config.yaml: | log_level: "debug" - controller_name: {{ .ControllerName | default "apisix.apache.org/apisix-ingress-controller" }} - leader_election_id: "apisix-ingress-controller-leader" - + exec_adc_timeout: 5s provider: type: {{ .ProviderType | default "apisix" }} sync_period: {{ .ProviderSyncPeriod | default "0s" }} diff --git a/test/e2e/gatewayapi/gatewayproxy.go b/test/e2e/gatewayapi/gatewayproxy.go index dfcbba9be2..f8fc56f771 100644 --- a/test/e2e/gatewayapi/gatewayproxy.go +++ b/test/e2e/gatewayapi/gatewayproxy.go @@ -123,25 +123,6 @@ spec: port: 80 ` - var resourceApplied = func(resourceType, resourceName, resourceRaw string, observedGeneration int) { - Expect(s.CreateResourceFromString(resourceRaw)). - NotTo(HaveOccurred(), fmt.Sprintf("creating %s", resourceType)) - - Eventually(func() string { - hryaml, err := s.GetResourceYaml(resourceType, resourceName) - Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("getting %s yaml", resourceType)) - return hryaml - }).WithTimeout(8*time.Second).ProbeEvery(2*time.Second). - Should( - SatisfyAll( - ContainSubstring(`status: "True"`), - ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), - ), - fmt.Sprintf("checking %s condition status", resourceType), - ) - time.Sleep(3 * time.Second) - } - var ( gatewayClassName string ) @@ -176,43 +157,40 @@ spec: Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controller"), "checking Gateway condition message") }) - AfterEach(func() { - By("Clean up resources") - _ = s.DeleteResourceFromString(fmt.Sprintf(httpRouteForTest, "apisix")) - _ = s.DeleteResourceFromString(fmt.Sprintf(gatewayWithProxy, gatewayClassName)) - _ = s.DeleteResourceFromString(fmt.Sprintf(gatewayProxyWithEnabledPlugin, s.Deployer.GetAdminEndpoint(), s.AdminKey())) - }) - Context("Test Gateway with enabled GatewayProxy plugin", func() { It("Should apply plugin configuration when enabled", func() { By("Create HTTPRoute for Gateway with GatewayProxy") - resourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) + s.ResourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) By("Check if the plugin is applied") - resp := s.NewAPISIXClient(). - GET("/get"). - WithHost("example.com"). - Expect(). - Status(200) - - resp.Header("X-Proxy-Test").IsEqual("enabled") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "example.com", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedHeader("X-Proxy-Test", "enabled"), + }, + }) By("Update GatewayProxy with disabled plugin") err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithDisabledPlugin, s.Deployer.GetAdminEndpoint(), s.AdminKey())) Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy with disabled plugin") - time.Sleep(5 * time.Second) By("Create HTTPRoute for Gateway with GatewayProxy") - resourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) + s.ResourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) By("Check if the plugin is not applied") - resp = s.NewAPISIXClient(). - GET("/get"). - WithHost("example.com"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "example.com", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedHeader("X-Proxy-Test", ""), + }, + }) - resp.Header("X-Proxy-Test").IsEmpty() }) }) @@ -238,20 +216,19 @@ spec: By("Update GatewayProxy with invalid endpoint") err := s.CreateResourceFromString(fmt.Sprintf(gatewayProxyWithInvalidEndpoint, s.Deployer.GetAdminEndpoint(), s.AdminKey())) Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy with enabled plugin") - time.Sleep(5 * time.Second) By("Create HTTPRoute") - resourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) - - expectRequest := func() bool { - resp := s.NewAPISIXClient(). - GET("/get"). - WithHost("example.com"). - Expect().Raw() - return resp.StatusCode == 200 && resp.Header.Get("X-Proxy-Test") == "" - } - - Eventually(expectRequest).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(BeTrue()) + s.ResourceApplied("HTTPRoute", "test-route", fmt.Sprintf(httpRouteForTest, "apisix"), 1) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "example.com", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(200), + scaffold.WithExpectedHeader("X-Proxy-Test", ""), + }, + }) }) }) @@ -311,12 +288,10 @@ spec: err := s.CreateResourceFromString(gatewayProxyWithValidProvider) Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy with valid provider") - Eventually(func() string { - gpYaml, err := s.GetResourceYaml("GatewayProxy", "apisix-proxy-config") - Expect(err).NotTo(HaveOccurred(), "getting GatewayProxy yaml") + s.RetryAssertion(func() string { + gpYaml, _ := s.GetResourceYaml("GatewayProxy", "apisix-proxy-config") return gpYaml - }).WithTimeout(8*time.Second).ProbeEvery(2*time.Second). - Should(ContainSubstring(`"type":"ControlPlane"`), "checking GatewayProxy is applied") + }).Should(ContainSubstring(`"type":"ControlPlane"`), "checking GatewayProxy is applied") }) }) }) diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index a634447e9e..daba664ee4 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -24,7 +24,6 @@ import ( "strings" "time" - "github.com/gruntwork-io/terratest/modules/retry" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/pkg/errors" @@ -112,86 +111,80 @@ spec: name: apisix-proxy-config ` - var ResourceApplied = func(resourType, resourceName, resourceRaw string, observedGeneration int) { - Expect(s.CreateResourceFromString(resourceRaw)). - NotTo(HaveOccurred(), fmt.Sprintf("creating %s", resourType)) - - Eventually(func() string { - hryaml, err := s.GetResourceYaml(resourType, resourceName) - Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("getting %s yaml", resourType)) - return hryaml - }, "8s", "2s"). - Should( - SatisfyAll( - ContainSubstring(`status: "True"`), - ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), - ), - fmt.Sprintf("checking %s condition status", resourType), - ) - time.Sleep(5 * time.Second) - } - var beforeEachHTTP = func() { - By("create GatewayProxy") - err := s.CreateResourceFromString(getGatewayProxySpec()) - Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") - time.Sleep(5 * time.Second) - - By("create GatewayClass") - gatewayClassName := fmt.Sprintf("apisix-%d", time.Now().Unix()) - err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayClassYaml, gatewayClassName, s.GetControllerName()), "") - Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") - time.Sleep(5 * time.Second) - - By("check GatewayClass condition") - gcyaml, err := s.GetResourceYaml("GatewayClass", gatewayClassName) - Expect(err).NotTo(HaveOccurred(), "getting GatewayClass yaml") - Expect(gcyaml).To(ContainSubstring(`status: "True"`), "checking GatewayClass condition status") - Expect(gcyaml).To(ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), "checking GatewayClass condition message") - - By("create Gateway") - err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defaultGateway, gatewayClassName), s.Namespace()) - Expect(err).NotTo(HaveOccurred(), "creating Gateway") - time.Sleep(5 * time.Second) - - By("check Gateway condition") - gwyaml, err := s.GetResourceYaml("Gateway", "apisix") - Expect(err).NotTo(HaveOccurred(), "getting Gateway yaml") - Expect(gwyaml).To(ContainSubstring(`status: "True"`), "checking Gateway condition status") - Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controller"), "checking Gateway condition message") + Expect(s.CreateResourceFromString(getGatewayProxySpec())). + NotTo(HaveOccurred(), "creating GatewayProxy") + + gatewayClassName := fmt.Sprintf("apisix-%d", time.Now().Nanosecond()) + Expect(s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayClassYaml, gatewayClassName, s.GetControllerName()), "")). + NotTo(HaveOccurred(), "creating GatewayClass") + + s.RetryAssertion(func() string { + gcyaml, _ := s.GetResourceYaml("GatewayClass", gatewayClassName) + return gcyaml + }).Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), + ), + "check GatewayClass condition", + ) + + Expect(s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defaultGateway, gatewayClassName), s.Namespace())). + NotTo(HaveOccurred(), "creating Gateway") + + s.RetryAssertion(func() string { + gcyaml, _ := s.GetResourceYaml("Gateway", "apisix") + return gcyaml + }).Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controlle"), + ), + "check Gateway condition status", + ) } var beforeEachHTTPS = func() { By("create GatewayProxy") err := s.CreateResourceFromString(getGatewayProxySpec()) Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") - time.Sleep(5 * time.Second) secretName := _secretName createSecret(s, secretName) - By("create GatewayClass") - gatewayClassName := fmt.Sprintf("apisix-%d", time.Now().Unix()) - err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayClassYaml, gatewayClassName, s.GetControllerName()), "") - Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") - time.Sleep(5 * time.Second) - By("check GatewayClass condition") - gcyaml, err := s.GetResourceYaml("GatewayClass", gatewayClassName) - Expect(err).NotTo(HaveOccurred(), "getting GatewayClass yaml") - Expect(gcyaml).To(ContainSubstring(`status: "True"`), "checking GatewayClass condition status") - Expect(gcyaml).To(ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), "checking GatewayClass condition message") + By("create GatewayClass") + gatewayClassName := fmt.Sprintf("apisix-%d", time.Now().Nanosecond()) + Expect(s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayClassYaml, gatewayClassName, s.GetControllerName()), "")). + NotTo(HaveOccurred(), "creating GatewayClass") + + s.RetryAssertion(func() string { + gcyaml, _ := s.GetResourceYaml("GatewayClass", gatewayClassName) + return gcyaml + }).Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), + ), + "check GatewayClass condition", + ) By("create Gateway") err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(defaultGatewayHTTPS, gatewayClassName), s.Namespace()) Expect(err).NotTo(HaveOccurred(), "creating Gateway") - time.Sleep(5 * time.Second) - By("check Gateway condition") - gwyaml, err := s.GetResourceYaml("Gateway", "apisix") - Expect(err).NotTo(HaveOccurred(), "getting Gateway yaml") - Expect(gwyaml).To(ContainSubstring(`status: "True"`), "checking Gateway condition status") - Expect(gwyaml).To(ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controller"), "checking Gateway condition message") + s.RetryAssertion(func() string { + gcyaml, _ := s.GetResourceYaml("Gateway", "apisix") + return gcyaml + }).Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring("message: the gateway has been accepted by the apisix-ingress-controlle"), + ), + "check Gateway condition status", + ) } + Context("HTTPRoute with HTTPS Gateway", func() { var exactRouteByGet = ` apiVersion: gateway.networking.k8s.io/v1 @@ -217,24 +210,26 @@ spec: It("Create/Updtea/Delete HTTPRoute", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("access dataplane to check the HTTPRoute") - s.NewAPISIXHttpsClient("api6.com"). - GET("/get"). - WithHost("api6.com"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "api6.com", + Check: scaffold.WithExpectedStatus(200), + }) + By("delete HTTPRoute") err := s.DeleteResourceFromString(exactRouteByGet) Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoute") - time.Sleep(5 * time.Second) - s.NewAPISIXHttpsClient("api6.com"). - GET("/get"). - WithHost("api6.com"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "api6.com", + Check: scaffold.WithExpectedStatus(404), + }) }) }) @@ -323,12 +318,17 @@ spec: additionalGatewayClassName = fmt.Sprintf("apisix-%d", time.Now().Unix()) err = s.CreateResourceFromStringWithNamespace(fmt.Sprintf(gatewayClassYaml, additionalGatewayClassName, s.GetControllerName()), "") Expect(err).NotTo(HaveOccurred(), "creating additional GatewayClass") - time.Sleep(5 * time.Second) + By("Check additional GatewayClass condition") - gcyaml, err := s.GetResourceYaml("GatewayClass", additionalGatewayClassName) - Expect(err).NotTo(HaveOccurred(), "getting additional GatewayClass yaml") - Expect(gcyaml).To(ContainSubstring(`status: "True"`), "checking additional GatewayClass condition status") - Expect(gcyaml).To(ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), "checking additional GatewayClass condition message") + s.RetryAssertion(func() string { + gcyaml, _ := s.GetResourceYaml("GatewayClass", additionalGatewayClassName) + return gcyaml + }).Should( + And( + ContainSubstring(`status: "True"`), + ContainSubstring("message: the gatewayclass has been accepted by the apisix-ingress-controller"), + ), + ) additionalGatewayProxy := fmt.Sprintf(additionalGatewayProxyYaml, s.Deployer.GetAdminEndpoint(resources.DataplaneService), resources.AdminAPIKey) err = s.CreateResourceFromStringWithNamespace(additionalGatewayProxy, resources.DataplaneService.Namespace) @@ -340,52 +340,56 @@ spec: additionalSvc.Namespace, ) Expect(err).NotTo(HaveOccurred(), "creating additional Gateway") - time.Sleep(5 * time.Second) }) It("HTTPRoute should be accessible through both gateways", func() { By("Create HTTPRoute referencing both gateways") multiGatewayRoute := fmt.Sprintf(multiGatewayHTTPRoute, s.Namespace(), additionalSvc.Namespace) - ResourceApplied("HTTPRoute", "multi-gateway-route", multiGatewayRoute, 1) + s.ResourceApplied("HTTPRoute", "multi-gateway-route", multiGatewayRoute, 1) By("Access through default gateway") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("Access through additional gateway") client, err := s.NewAPISIXClientForGateway(additionalGatewayGroupID) Expect(err).NotTo(HaveOccurred(), "creating client for additional gateway") - client. - GET("/get"). - WithHost("httpbin-additional.example"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin-additional.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("Delete Additional Gateway") err = s.DeleteResourceFromStringWithNamespace(fmt.Sprintf(additionalGateway, additionalGatewayClassName), additionalSvc.Namespace) Expect(err).NotTo(HaveOccurred(), "deleting additional Gateway") - time.Sleep(5 * time.Second) By("HTTPRoute should still be accessible through default gateway") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("HTTPRoute should not be accessible through additional gateway") client, err = s.NewAPISIXClientForGateway(additionalGatewayGroupID) Expect(err).NotTo(HaveOccurred(), "creating client for additional gateway") - client. - GET("/get"). - WithHost("httpbin-additional.example"). - Expect(). - Status(http.StatusNotFound) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin-additional.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) }) @@ -397,7 +401,7 @@ metadata: name: httpbin-external-domain spec: type: ExternalName - externalName: postman-echo.com + externalName: httpbin-service-e2e-test --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -501,121 +505,136 @@ spec: It("Create/Update/Delete HTTPRoute", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("access dataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/get"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) - By("delete HTTPRoute") - err := s.DeleteResourceFromString(exactRouteByGet) - Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoute") - time.Sleep(5 * time.Second) + Expect(s.DeleteResourceFromString(exactRouteByGet)). + NotTo(HaveOccurred(), "deleting HTTPRoute") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) It("Delete Gateway after apply HTTPRoute", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("access dataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - By("delete Gateway") - err := s.DeleteResource("Gateway", "apisix") - Expect(err).NotTo(HaveOccurred(), "deleting Gateway") - - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Raw().StatusCode - }).WithTimeout(5 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + Expect(s.DeleteResource("Gateway", "apisix")). + NotTo(HaveOccurred(), "deleting Gateway") + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) It("Proxy External Service", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", httprouteWithExternalName, 1) + s.ResourceApplied("HTTPRoute", "httpbin", httprouteWithExternalName, 1) By("checking the external service response") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.external"). - Expect(). - Status(http.StatusMovedPermanently) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.external", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) }) It("Match Port", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", invalidBackendPort, 1) + s.ResourceApplied("HTTPRoute", "httpbin", invalidBackendPort, 1) - serviceResources, err := s.DefaultDataplaneResource().Service().List(context.Background()) - Expect(err).NotTo(HaveOccurred(), "listing services") - Expect(serviceResources).To(HaveLen(1), "checking service length") + s.RetryAssertion(func() error { + serviceResources, err := s.DefaultDataplaneResource().Service().List(context.Background()) + if err != nil { + return errors.Wrap(err, "listing services") + } + if len(serviceResources) != 1 { + return fmt.Errorf("expected 1 service, got %d", len(serviceResources)) + } - serviceResource := serviceResources[0] - nodes := serviceResource.Upstream.Nodes - Expect(nodes).To(HaveLen(1), "checking nodes length") - Expect(nodes[0].Port).To(Equal(80)) + serviceResource := serviceResources[0] + nodes := serviceResource.Upstream.Nodes + if len(nodes) != 1 { + return fmt.Errorf("expected 1 node, got %d", len(nodes)) + } + if nodes[0].Port != 80 { + return fmt.Errorf("expected node port 80, got %d", nodes[0].Port) + } + return nil + }).Should(Succeed(), "checking service port") }) It("Delete HTTPRoute during restart", func() { By("create HTTPRoute httpbin") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("create HTTPRoute httpbin2") - ResourceApplied("HTTPRoute", "httpbin2", exactRouteByGet2, 1) + s.ResourceApplied("HTTPRoute", "httpbin2", exactRouteByGet2, 1) - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin2.example"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin2.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) s.Deployer.ScaleIngress(0) - By("delete HTTPRoute httpbin2") - err := s.DeleteResource("HTTPRoute", "httpbin2") - Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoute httpbin2") + Expect(s.DeleteResource("HTTPRoute", "httpbin2")). + NotTo(HaveOccurred(), "deleting HTTPRoute httpbin2") s.Deployer.ScaleIngress(1) - time.Sleep(1 * time.Minute) - - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin2.example"). - Expect(). - Status(404) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Timeout: 1 * time.Minute, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin2.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) }) @@ -736,92 +755,106 @@ spec: It("HTTPRoute Exact Match", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("access daataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/get/xxx"). - WithHost("httpbin.example"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get/xxx", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) It("HTTPRoute Prefix Match", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", prefixRouteByStatus, 1) + s.ResourceApplied("HTTPRoute", "httpbin", prefixRouteByStatus, 1) By("access daataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/status/200"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - GET("/status/201"). - WithHost("httpbin.example"). - Expect(). - Status(201) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/status/200", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/status/201", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusCreated), + }) }) It("HTTPRoute Method Match", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", methodRouteGETAndDELETEByAnything, 1) + s.ResourceApplied("HTTPRoute", "httpbin", methodRouteGETAndDELETEByAnything, 1) By("access daataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/anything"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - DELETE("/anything"). - WithHost("httpbin.example"). - Expect(). - Status(200) - - s.NewAPISIXClient(). - POST("/anything"). - WithHost("httpbin.example"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/anything", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "DELETE", + Path: "/anything", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "POST", + Path: "/anything", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) }) It("HTTPRoute Vars Match", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", varsRoute, 1) + s.ResourceApplied("HTTPRoute", "httpbin", varsRoute, 1) By("access dataplane to check the HTTPRoute") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(http.StatusNotFound) - - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) }) It("HTTPRoutePolicy in effect", func() { By("create HTTPRoute") s.ApplyHTTPRoute(types.NamespacedName{Namespace: s.Namespace(), Name: "httpbin"}, varsRoute) - request := func() int { - return s.NewAPISIXClient().GET("/get"). - WithHost("httpbin.example").WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - } - Eventually(request).WithTimeout(5 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("create HTTPRoutePolicy") s.ApplyHTTPRoutePolicy( @@ -831,16 +864,29 @@ spec: ) By("access dataplane to check the HTTPRoutePolicy") - Eventually(request).WithTimeout(5 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - WithHeader("X-HRP-Name", "http-route-policy-0"). - WithQuery("hrp_name", "http-route-policy-0"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Query: map[string]any{ + "hrp_name": "http-route-policy-0", + }, + Headers: map[string]string{ + "X-Route-Name": "httpbin", + "X-HRP-Name": "http-route-policy-0", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("update HTTPRoutePolicy") const changedHTTPRoutePolicy = ` @@ -867,24 +913,31 @@ spec: ) // use the old vars cannot match any route - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - WithHeader("X-HRP-Name", "http-route-policy-0"). - WithQuery("hrp_name", "http-route-policy-0"). - Expect().Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Query: map[string]any{ + "hrp_name": "http-route-policy-0", + }, + Headers: map[string]string{ + "X-Route-Name": "httpbin", + "X-HRP-Name": "http-route-policy-0", + }, + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) // use the new vars can match the route - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - WithHeader("X-HRP-Name", "new-hrp-name"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + "X-HRP-Name": "new-hrp-name", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("delete the HTTPRoutePolicy") err := s.DeleteResource("HTTPRoutePolicy", "http-route-policy-0") @@ -894,18 +947,15 @@ spec: return err.Error() }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(ContainSubstring(`httproutepolicies.apisix.apache.org "http-route-policy-0" not found`)) // access the route without additional vars should be OK - message := retry.DoWithRetry(s.GinkgoT, "", 10, time.Second, func() (string, error) { - statusCode := s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - if statusCode != http.StatusOK { - return "", errors.Errorf("unexpected status code: %v", statusCode) - } - return "request OK", nil + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), }) - s.Logf(message) }) It("HTTPRoutePolicy conflicts", func() { @@ -1007,13 +1057,15 @@ spec: } // assert that conflict policies are not in effect - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("delete HTTPRoutePolicies") err := s.DeleteResource("HTTPRoutePolicy", "http-route-policy-2") @@ -1029,13 +1081,15 @@ spec: }, ) } - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) By("update HTTPRoutePolicy") err = s.CreateResourceFromString(httpRoutePolicy1Priority20) @@ -1058,13 +1112,16 @@ spec: }, ) } - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) }) It("HTTPRoutePolicy status changes on HTTPRoute deleting", func() { @@ -1079,42 +1136,49 @@ spec: ) By("access dataplane to check the HTTPRoutePolicy") - Eventually(func() int { - return s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - Expect().Raw().StatusCode - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) - - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - WithHeader("X-HRP-Name", "http-route-policy-0"). - WithQuery("hrp_name", "http-route-policy-0"). - Expect(). - Status(http.StatusOK) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Route-Name": "httpbin", + }, + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Query: map[string]any{ + "hrp_name": "http-route-policy-0", + }, + Headers: map[string]string{ + "X-Route-Name": "httpbin", + "X-HRP-Name": "http-route-policy-0", + }, + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("delete the HTTPRoute, assert the HTTPRoutePolicy's status will be changed") - err := s.DeleteResource("HTTPRoute", "httpbin") - Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoute") - message := retry.DoWithRetry(s.GinkgoT, "request the deleted route", 10, time.Second, func() (string, error) { - statusCode := s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - WithHeader("X-Route-Name", "httpbin"). - WithHeader("X-HRP-Name", "http-route-policy-0"). - WithQuery("hrp_name", "http-route-policy-0"). - Expect().Raw().StatusCode - if statusCode != http.StatusNotFound { - return "", errors.Errorf("unexpected status code: %v", statusCode) - } - return "the route is deleted", nil + Expect(s.DeleteResource("HTTPRoute", "httpbin")). + NotTo(HaveOccurred(), "deleting HTTPRoute") + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Query: map[string]any{ + "hrp_name": "http-route-policy-0", + }, + Headers: map[string]string{ + "X-Route-Name": "httpbin", + "X-HRP-Name": "http-route-policy-0", + }, + Check: scaffold.WithExpectedStatus(http.StatusNotFound), }) - s.Logf(message) - err = framework.PollUntilHTTPRoutePolicyHaveStatus(s.K8sClient, 8*time.Second, types.NamespacedName{Namespace: s.Namespace(), Name: "http-route-policy-0"}, + err := framework.PollUntilHTTPRoutePolicyHaveStatus(s.K8sClient, 8*time.Second, types.NamespacedName{Namespace: s.Namespace(), Name: "http-route-policy-0"}, func(hrp *v1alpha1.HTTPRoutePolicy) bool { return len(hrp.Status.Ancestors) == 0 }, @@ -1335,63 +1399,73 @@ spec: It("HTTPRoute RequestHeaderModifier", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", reqHeaderModifyByHeaders, 1) + s.ResourceApplied("HTTPRoute", "httpbin", reqHeaderModifyByHeaders, 1) By("access daataplane to check the HTTPRoute") - respExp := s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.example"). - WithHeader("X-Req-Add", "test"). - WithHeader("X-Req-Removed", "test"). - WithHeader("X-Req-Set", "test"). - Expect() - - respExp.Status(200) - respExp.Body(). - Contains(`"X-Req-Add": "test,add"`). - Contains(`"X-Req-Set": "set"`). - NotContains(`"X-Req-Removed": "remove"`) - + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.example", + Headers: map[string]string{ + "X-Req-Add": "test", + "X-Req-Removed": "test", + "X-Req-Set": "test", + }, + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusOK), + scaffold.WithExpectedBodyContains(`"X-Req-Add": "test,add"`, `"X-Req-Set": "set"`), + scaffold.WithExpectedBodyNotContains(`"X-Req-Removed": "remove"`), + }, + }) }) It("HTTPRoute ResponseHeaderModifier", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", respHeaderModifyByHeaders, 1) + s.ResourceApplied("HTTPRoute", "httpbin", respHeaderModifyByHeaders, 1) By("access daataplane to check the HTTPRoute") - respExp := s.NewAPISIXClient(). - GET("/headers"). - WithHost("httpbin.example"). - Expect() - - respExp.Status(200) - respExp.Header("X-Resp-Add").IsEqual("add") - respExp.Header("X-Resp-Set").IsEqual("set") - respExp.Header("Server").IsEmpty() - respExp.Body(). - NotContains(`"X-Resp-Add": "add"`). - NotContains(`"X-Resp-Set": "set"`). - NotContains(`"Server"`) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusOK), + scaffold.WithExpectedHeaders(map[string]string{ + "X-Resp-Add": "add", + "X-Resp-Set": "set", + "Server": "", + }), + scaffold.WithExpectedBodyNotContains(`"X-Resp-Add": "add"`, `"X-Resp-Set": "set"`, `"Server"`), + }, + }) }) It("HTTPRoute RequestRedirect", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", httpsRedirectByHeaders, 1) - - s.NewAPISIXClient().GET("/headers"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusFound). - Header("Location").IsEqual("https://httpbin.example:9443/headers") + s.ResourceApplied("HTTPRoute", "httpbin", httpsRedirectByHeaders, 1) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusFound), + scaffold.WithExpectedHeader("Location", "https://httpbin.example:9443/headers"), + }, + }) By("update HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", hostnameRedirectByHeaders, 2) - - s.NewAPISIXClient().GET("/headers"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusMovedPermanently). - Header("Location").IsEqual("http://httpbin.org/headers") + s.ResourceApplied("HTTPRoute", "httpbin", hostnameRedirectByHeaders, 2) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/headers", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusMovedPermanently), + scaffold.WithExpectedHeader("Location", "http://httpbin.org/headers"), + }, + }) }) It("HTTPRoute RequestMirror", func() { @@ -1453,78 +1527,89 @@ spec: - name: httpbin-service-e2e-test port: 80 ` - ResourceApplied("HTTPRoute", "httpbin", echoRoute, 1) - - time.Sleep(time.Second * 6) - - _ = s.NewAPISIXClient().GET("/headers"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusOK) + s.ResourceApplied("HTTPRoute", "httpbin", echoRoute, 1) - echoLogs := s.GetDeploymentLogs("echo") - Expect(echoLogs).To(ContainSubstring("GET /headers")) + s.RetryAssertion(func() string { + resp := s.NewAPISIXClient().GET("/headers").WithHost("httpbin.example").Expect().Raw() + if resp.StatusCode != http.StatusOK { + return fmt.Sprintf("expected status OK, got %d", resp.StatusCode) + } + return s.GetDeploymentLogs("echo") + }).WithTimeout(2 * time.Minute).Should(ContainSubstring("GET /headers")) }) It("HTTPRoute URLRewrite with ReplaceFullPath And Hostname", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", replaceFullPathAndHost, 1) + s.ResourceApplied("HTTPRoute", "httpbin", replaceFullPathAndHost, 1) By("/replace/201 should be rewritten to /headers") - s.NewAPISIXClient().GET("/replace/201"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusOK). - Body(). - Contains("replace.example.org") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/replace/201", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusOK), + scaffold.WithExpectedBodyContains("replace.example.org"), + }, + }) By("/replace/500 should be rewritten to /headers") - s.NewAPISIXClient().GET("/replace/500"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusOK). - Body(). - Contains("replace.example.org") + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/replace/500", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusOK), + scaffold.WithExpectedBodyContains("replace.example.org"), + }, + }) }) It("HTTPRoute URLRewrite with ReplacePrefixMatch", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", replacePrefixMatch, 1) + s.ResourceApplied("HTTPRoute", "httpbin", replacePrefixMatch, 1) By("/replace/201 should be rewritten to /status/201") - s.NewAPISIXClient().GET("/replace/201"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusCreated) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/replace/201", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusCreated), + }) By("/replace/500 should be rewritten to /status/500") - s.NewAPISIXClient().GET("/replace/500"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusInternalServerError) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/replace/500", + Host: "httpbin.example", + Checks: []scaffold.ResponseCheckFunc{ + scaffold.WithExpectedStatus(http.StatusInternalServerError), + }, + }) }) It("HTTPRoute ExtensionRef", func() { By("create HTTPRoute") - err := s.CreateResourceFromString(echoPlugin) - Expect(err).NotTo(HaveOccurred(), "creating PluginConfig") - ResourceApplied("HTTPRoute", "httpbin", extensionRefEchoPlugin, 1) - - s.NewAPISIXClient().GET("/get"). - WithHeader("Host", "httpbin.example"). - Expect(). - Body(). - Contains("Hello, World!!") - - err = s.CreateResourceFromString(echoPluginUpdated) - Expect(err).NotTo(HaveOccurred(), "updating PluginConfig") - time.Sleep(5 * time.Second) + Expect(s.CreateResourceFromString(echoPlugin)). + NotTo(HaveOccurred(), "creating PluginConfig") + s.ResourceApplied("HTTPRoute", "httpbin", extensionRefEchoPlugin, 1) + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedBodyContains("Hello, World!!"), + }) - s.NewAPISIXClient().GET("/get"). - WithHeader("Host", "httpbin.example"). - Expect(). - Body(). - Contains("Updated") + Expect(s.CreateResourceFromString(echoPluginUpdated)). + NotTo(HaveOccurred(), "updating PluginConfig") + + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedBodyContains("Updated"), + }) }) }) @@ -1583,45 +1668,58 @@ spec: }) }) It("HTTPRoute Canary", func() { - ResourceApplied("HTTPRoute", "httpbin", sameWeiht, 1) + s.ResourceApplied("HTTPRoute", "httpbin", sameWeiht, 1) + time.Sleep(5 * time.Second) - var ( - hitNginxCnt = 0 - hitHttpbinCnt = 0 - ) - for i := 0; i < 100; i++ { - body := s.NewAPISIXClient().GET("/get"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusOK). - Body().Raw() - - if strings.Contains(body, "Hello") { - hitNginxCnt++ - } else { - hitHttpbinCnt++ + s.RetryAssertion(func() int { + var ( + hitNginxCnt = 0 + hitHttpbinCnt = 0 + ) + for i := 0; i < 20; i++ { + resp := s.NewAPISIXClient().GET("/get"). + WithHeader("Host", "httpbin.example"). + Expect() + body := resp.Body().Raw() + status := resp.Raw().StatusCode + if status != http.StatusOK { + return -100 + } + + if strings.Contains(body, "Hello") { + hitNginxCnt++ + } else { + hitHttpbinCnt++ + } } - } - Expect(hitNginxCnt - hitHttpbinCnt).To(BeNumerically("~", 0, 2)) - - ResourceApplied("HTTPRoute", "httpbin", oneWeiht, 2) - - hitNginxCnt = 0 - hitHttpbinCnt = 0 - for i := 0; i < 100; i++ { - body := s.NewAPISIXClient().GET("/get"). - WithHeader("Host", "httpbin.example"). - Expect(). - Status(http.StatusOK). - Body().Raw() - - if strings.Contains(body, "Hello") { - hitNginxCnt++ - } else { - hitHttpbinCnt++ + return hitNginxCnt - hitHttpbinCnt + }).WithTimeout(2 * time.Minute).Should(BeNumerically("~", 0, 2)) + + s.ResourceApplied("HTTPRoute", "httpbin", oneWeiht, 2) + + s.RetryAssertion(func() int { + var ( + hitNginxCnt = 0 + hitHttpbinCnt = 0 + ) + for i := 0; i < 20; i++ { + resp := s.NewAPISIXClient().GET("/get"). + WithHeader("Host", "httpbin.example"). + Expect() + body := resp.Body().Raw() + status := resp.Raw().StatusCode + if status != http.StatusOK { + return -100 + } + + if strings.Contains(body, "Hello") { + hitNginxCnt++ + } else { + hitHttpbinCnt++ + } } - } - Expect(hitHttpbinCnt - hitNginxCnt).To(Equal(100)) + return hitHttpbinCnt - hitNginxCnt + }).WithTimeout(2 * time.Minute).Should(Equal(20)) }) }) @@ -1669,14 +1767,15 @@ spec: It("Should sync HTTPRoute when GatewayProxy is updated", func() { By("create HTTPRoute") - ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + s.ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) By("verify HTTPRoute works") - s.NewAPISIXClient(). - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) By("create additional gateway group to get new admin key") var err error @@ -1690,24 +1789,27 @@ spec: Expect(err).NotTo(HaveOccurred(), "creating APISIX client for additional gateway group") By("HTTPRoute not found for additional gateway group") - client. - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(404) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusNotFound), + }) By("update GatewayProxy with new admin key") updatedProxy := fmt.Sprintf(updatedGatewayProxy, s.Deployer.GetAdminEndpoint(resources.DataplaneService), resources.AdminAPIKey) err = s.CreateResourceFromString(updatedProxy) Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") - time.Sleep(5 * time.Second) By("verify HTTPRoute works for additional gateway group") - client. - GET("/get"). - WithHost("httpbin.example"). - Expect(). - Status(200) + s.RequestAssert(&scaffold.RequestAssert{ + Client: client, + Method: "GET", + Path: "/get", + Host: "httpbin.example", + Check: scaffold.WithExpectedStatus(http.StatusOK), + }) }) }) @@ -1721,7 +1823,7 @@ metadata: name: httpbin-external-domain spec: type: ExternalName - externalName: httpbin.org + externalName: httpbin-service-e2e-test --- apiVersion: v1 kind: Service @@ -1744,7 +1846,7 @@ spec: kind: Service group: "" passHost: node - scheme: https + scheme: http --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -1760,10 +1862,10 @@ spec: value: /headers backendRefs: - name: httpbin-external-domain - port: 443 + port: 80 weight: 1 - name: mockapi7-external-domain - port: 443 + port: 80 weight: 1 ` @@ -1778,22 +1880,14 @@ spec: totalRequests := 20 for i := 0; i < totalRequests; i++ { - resp := s.NewAPISIXClient().GET("/headers").Expect().Status(http.StatusOK) - - // Parse JSON response to get the Host header - var responseBody map[string]any - resp.JSON().Decode(&responseBody) - - if headers, ok := responseBody["headers"].(map[string]any); ok { - var host string - if host, ok = headers["Host"].(string); !ok { - host, ok = headers["host"].(string) - } - if ok && host != "" { - upstreamHosts[host]++ - } - Expect(ok).To(BeTrue(), "Host header should be present") - Expect(host).Should(Or(Equal("httpbin.org"), Equal("mock.api7.ai"))) + statusCode := s.NewAPISIXClient().GET("/headers").Expect().Raw().StatusCode + Expect(statusCode).To(Or(Equal(http.StatusOK), Equal(http.StatusMovedPermanently))) + + switch statusCode { + case http.StatusOK: + upstreamHosts["httpbin-service-e2e-test"]++ + case http.StatusMovedPermanently: + upstreamHosts["mock.api7.ai"]++ } time.Sleep(100 * time.Millisecond) // Small delay between requests } @@ -1806,16 +1900,4 @@ spec: } }) }) - - /* - Context("HTTPRoute Status Updated", func() { - }) - - Context("HTTPRoute ParentRefs With Multiple Gateway", func() { - }) - - - Context("HTTPRoute BackendRefs Discovery", func() { - }) - */ }) diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index 0c85c53291..6b537b9897 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -186,7 +186,7 @@ metadata: name: httpbin-external-domain spec: type: ExternalName - externalName: postman-echo.com + externalName: httpbin-service-e2e-test --- apiVersion: networking.k8s.io/v1 kind: Ingress @@ -253,7 +253,7 @@ spec: GET("/get"). WithHost("httpbin.external"). Expect(). - Status(http.StatusMovedPermanently) + Status(http.StatusOK) }) It("Delete Ingress during restart", func() { @@ -283,7 +283,7 @@ spec: GET("/get"). WithHost("httpbin.external"). Expect(). - Status(http.StatusMovedPermanently) + Status(http.StatusOK) s.NewAPISIXClient(). GET("/get"). @@ -304,7 +304,7 @@ spec: GET("/get"). WithHost("httpbin.external"). Expect(). - Status(http.StatusMovedPermanently) + Status(http.StatusOK) s.NewAPISIXClient(). GET("/get"). diff --git a/test/e2e/scaffold/apisix_deployer.go b/test/e2e/scaffold/apisix_deployer.go index b6fe7febcf..e3e8b90a11 100644 --- a/test/e2e/scaffold/apisix_deployer.go +++ b/test/e2e/scaffold/apisix_deployer.go @@ -53,7 +53,7 @@ type APISIXDeployer struct { adminTunnel *k8s.Tunnel } -func NewAPISIXDeployer(s *Scaffold) *APISIXDeployer { +func NewAPISIXDeployer(s *Scaffold) Deployer { return &APISIXDeployer{ Scaffold: s, } @@ -66,7 +66,7 @@ func (s *APISIXDeployer) BeforeEach() { Namespace: s.namespace, } if s.opts.ControllerName == "" { - s.opts.ControllerName = fmt.Sprintf("%s/%d", DefaultControllerName, time.Now().Nanosecond()) + s.opts.ControllerName = fmt.Sprintf("%s/%s", DefaultControllerName, s.namespace) } s.finalizers = nil if s.label == nil { @@ -130,14 +130,14 @@ func (s *APISIXDeployer) AfterEach() { Expect(err).NotTo(HaveOccurred(), "cleaning up additional gateway") } - // if the test case is successful, just delete namespace - err := k8s.DeleteNamespaceE(s.t, s.kubectlOptions, s.namespace) - Expect(err).NotTo(HaveOccurred(), "deleting namespace "+s.namespace) - for i := len(s.finalizers) - 1; i >= 0; i-- { runWithRecover(s.finalizers[i]) } + // if the test case is successful, just delete namespace + err := k8s.DeleteNamespaceE(s.t, s.kubectlOptions, s.namespace) + Expect(err).NotTo(HaveOccurred(), "deleting namespace "+s.namespace) + // Wait for a while to prevent the worker node being overwhelming // (new cases will be run). time.Sleep(3 * time.Second) diff --git a/test/e2e/scaffold/assertion.go b/test/e2e/scaffold/assertion.go new file mode 100644 index 0000000000..c8946f2fd0 --- /dev/null +++ b/test/e2e/scaffold/assertion.go @@ -0,0 +1,252 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package scaffold + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gavv/httpexpect/v2" + . "github.com/onsi/gomega" //nolint:staticcheck + "github.com/onsi/gomega/types" +) + +const ( + DefaultTimeout = 12 * time.Second + DefaultInterval = 1 * time.Second +) + +type ResponseCheckFunc func(*HTTPResponse) error + +type HTTPResponse struct { + *http.Response + + Body string +} + +type BasicAuth struct { + Username string + Password string +} + +type RequestAssert struct { + Client *httpexpect.Expect + Method string + Path string + Host string + Query map[string]any + Headers map[string]string + Body []byte + BasicAuth *BasicAuth + + Timeout time.Duration + Interval time.Duration + + Check ResponseCheckFunc + Checks []ResponseCheckFunc +} + +func (c *RequestAssert) request(method, path string, body []byte) *httpexpect.Request { + switch strings.ToUpper(method) { + case "GET": + return c.Client.GET(path) + case "POST": + return c.Client.POST(path).WithBytes(body) + case "PUT": + return c.Client.PUT(path).WithBytes(body) + case "DELETE": + return c.Client.DELETE(path) + case "PATCH": + return c.Client.PATCH(path).WithBytes(body) + default: + panic("unsupported method: " + method) + } +} + +func (c *RequestAssert) WithCheck(check ResponseCheckFunc) *RequestAssert { + c.Checks = append(c.Checks, check) + return c +} + +func (c *RequestAssert) WithChecks(checks ...ResponseCheckFunc) *RequestAssert { + c.Checks = append(c.Checks, checks...) + return c +} + +func (c *RequestAssert) SetChecks(checks ...ResponseCheckFunc) *RequestAssert { + c.Checks = checks + return c +} + +func WithExpectedStatus(status int) ResponseCheckFunc { + return func(resp *HTTPResponse) error { + if resp.StatusCode != status { + return fmt.Errorf("expected %d, but got %d", status, resp.StatusCode) + } + return nil + } +} + +func WithExpectedBodyContains(expectedBodyList ...string) ResponseCheckFunc { + return func(resp *HTTPResponse) error { + for _, body := range expectedBodyList { + if !strings.Contains(resp.Body, body) { + return fmt.Errorf("expected body to contain %q, but got %q", body, resp.Body) + } + } + return nil + } +} + +func WithExpectedBodyNotContains(unexpectedBodyList ...string) ResponseCheckFunc { + return func(resp *HTTPResponse) error { + for _, unexpectedBody := range unexpectedBodyList { + if strings.Contains(resp.Body, unexpectedBody) { + return fmt.Errorf("expected body not to contain %q, but got %q", unexpectedBody, resp.Body) + } + } + return nil + } +} + +func WithExpectedHeader(key, value string) ResponseCheckFunc { + return func(resp *HTTPResponse) error { + if resp.Header.Get(key) != value { + return fmt.Errorf("expected header %q to be %q, but got %q", + key, value, resp.Header.Get(key)) + } + return nil + } +} + +func WithExpectedHeaders(expectedHeaders map[string]string) ResponseCheckFunc { + return func(resp *HTTPResponse) error { + for key, expectedValue := range expectedHeaders { + actualValue := resp.Header.Get(key) + if actualValue != expectedValue { + return fmt.Errorf("expected header %q to be %q, but got %q", + key, expectedValue, actualValue) + } + } + return nil + } +} + +func (s *Scaffold) RequestAssert(r *RequestAssert) bool { + if r.Client == nil { + r.Client = s.NewAPISIXClient() + } + if r.Method == "" { + if len(r.Body) > 0 { + r.Method = "POST" + } else { + r.Method = "GET" + } + } + if r.Timeout == 0 { + r.Timeout = DefaultTimeout + } + if r.Interval == 0 { + r.Interval = DefaultInterval + } + if r.Check == nil && len(r.Checks) == 0 { + r.Check = WithExpectedStatus(http.StatusOK) + } else if r.Check != nil { + r.Checks = append(r.Checks, r.Check) + } + + return EventuallyWithOffset(1, func() error { + req := r.request(r.Method, r.Path, r.Body) + if len(r.Headers) > 0 { + req = req.WithHeaders(r.Headers) + } + if r.Host != "" { + req = req.WithHost(r.Host) + } + if len(r.Query) > 0 { + for key, value := range r.Query { + req = req.WithQuery(key, value) + } + } + if r.BasicAuth != nil { + req = req.WithBasicAuth(r.BasicAuth.Username, r.BasicAuth.Password) + } + expResp := req.Expect() + + resp := &HTTPResponse{ + Response: expResp.Raw(), + Body: expResp.Body().Raw(), + } + + for _, check := range r.Checks { + if err := check(resp); err != nil { + return fmt.Errorf("response check failed: %w", err) + } + } + return nil + }).WithTimeout(r.Timeout).ProbeEvery(r.Interval).Should(Succeed()) +} + +// RetryAssertion provides a reusable Eventually-based assertion +type RetryAssertion struct { + timeout time.Duration + interval time.Duration + + args []any + actualOrCtx any +} + +// NewRetryAssertion creates a RetryAssertion with defaults +func (s *Scaffold) RetryAssertion(actualOrCtx any, args ...any) *RetryAssertion { + return &RetryAssertion{ + timeout: DefaultTimeout, + interval: DefaultInterval, + args: args, + actualOrCtx: actualOrCtx, + } +} + +// WithTimeout sets the timeout +func (r *RetryAssertion) WithTimeout(timeout time.Duration) *RetryAssertion { + r.timeout = timeout + return r +} + +// WithInterval sets the polling interval +func (r *RetryAssertion) WithInterval(interval time.Duration) *RetryAssertion { + r.interval = interval + return r +} + +// Should runs the Eventually assertion with the given matcher +func (r *RetryAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...any) bool { + return EventuallyWithOffset(1, r.actualOrCtx, r.args...). + WithTimeout(r.timeout). + ProbeEvery(r.interval). + Should(matcher, optionalDescription...) +} + +// ShouldNot runs the Eventually assertion with the given matcher +func (r *RetryAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...any) bool { + return EventuallyWithOffset(1, r.actualOrCtx, r.args...). + WithTimeout(r.timeout). + ProbeEvery(r.interval). + ShouldNot(matcher, optionalDescription...) +} diff --git a/test/e2e/scaffold/k8s.go b/test/e2e/scaffold/k8s.go index 890552c7a0..0612d4c09b 100644 --- a/test/e2e/scaffold/k8s.go +++ b/test/e2e/scaffold/k8s.go @@ -184,19 +184,17 @@ func (s *Scaffold) ResourceApplied(resourType, resourceName, resourceRaw string, Expect(s.CreateResourceFromString(resourceRaw)). NotTo(HaveOccurred(), fmt.Sprintf("creating %s", resourType)) - Eventually(func() string { + s.RetryAssertion(func() string { hryaml, err := s.GetResourceYaml(resourType, resourceName) Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("getting %s yaml", resourType)) return hryaml - }).WithTimeout(8*time.Second).ProbeEvery(2*time.Second). - Should( - SatisfyAll( - ContainSubstring(`status: "True"`), - ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), - ), - fmt.Sprintf("checking %s condition status", resourType), - ) - time.Sleep(3 * time.Second) + }).Should( + SatisfyAll( + ContainSubstring(`status: "True"`), + ContainSubstring(fmt.Sprintf("observedGeneration: %d", observedGeneration)), + ), + fmt.Sprintf("checking %s condition status", resourType), + ) } func (s *Scaffold) ApplyDefaultGatewayResource(