diff --git a/go.mod b/go.mod index 1b7f8da633..fa6c71e102 100644 --- a/go.mod +++ b/go.mod @@ -105,6 +105,7 @@ require ( github.com/google/s2a-go v0.1.4 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/hashicorp/consul/sdk v0.16.0 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -158,7 +159,7 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/cli v23.0.1+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v23.0.1+incompatible // indirect @@ -251,7 +252,7 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect @@ -291,7 +292,7 @@ require ( golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.11.0 // indirect diff --git a/go.sum b/go.sum index 65d127ad61..c3a9cb8c6a 100644 --- a/go.sum +++ b/go.sum @@ -407,6 +407,8 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -753,6 +755,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= 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= @@ -1033,6 +1037,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU= @@ -1572,6 +1578,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/test/functional-portable/cli/noncloud/cli_test.go b/test/functional-portable/cli/noncloud/cli_test.go index 981530cab3..8f8de191b6 100644 --- a/test/functional-portable/cli/noncloud/cli_test.go +++ b/test/functional-portable/cli/noncloud/cli_test.go @@ -33,6 +33,7 @@ import ( "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/go-retryablehttp" "github.com/radius-project/radius/pkg/cli/bicep" "github.com/radius-project/radius/pkg/cli/clients" @@ -59,7 +60,7 @@ const ( retries = 10 ) -func verifyRecipeCLI(ctx context.Context, t *testing.T, test shared.RPTest) { +func verifyRecipeCLI(ctx context.Context, t retry.TestingTB, test shared.RPTest) { options := shared.NewRPTestOptions(t) cli := radcli.NewCLI(t, options.ConfigFilePath) envName := test.Steps[0].RPResources.Resources[0].Name @@ -80,82 +81,82 @@ func verifyRecipeCLI(ctx context.Context, t *testing.T, test shared.RPTest) { terraformRecipeTemplate := "Azure/cosmosdb/azurerm" templateKindTerraform := "terraform" - t.Run("Validate rad recipe register", func(t *testing.T) { - output, err := cli.RecipeRegister(ctx, envName, recipeName, templateKindBicep, recipeTemplate, resourceType, false) - require.NoError(t, err) - require.Contains(t, output, "Successfully linked recipe") - }) - - t.Run("Validate rad recipe register with insecure registry", func(t *testing.T) { - output, err := cli.RecipeRegister(ctx, envName, recipeName, templateKindBicep, recipeTemplate, resourceType, true) - require.NoError(t, err) - require.Contains(t, output, "Successfully linked recipe") - }) - - t.Run("Validate rad recipe list", func(t *testing.T) { - output, err := cli.RecipeList(ctx, envName) - require.NoError(t, err) - require.Regexp(t, bicepRecipe, output) - require.Regexp(t, terraformRecipe, output) - require.Regexp(t, recipeName, output) - require.Regexp(t, resourceType, output) - require.Regexp(t, bicepRecipeTemplate, output) - require.Regexp(t, terraformRecipeTemplate, output) - require.Regexp(t, recipeTemplate, output) - require.Regexp(t, templateKindBicep, output) - require.Regexp(t, templateKindTerraform, output) - }) - - t.Run("Validate rad recipe unregister", func(t *testing.T) { - output, err := cli.RecipeUnregister(ctx, envName, recipeName, resourceType) - require.NoError(t, err) - require.Contains(t, output, "Successfully unregistered recipe") - }) + // t.Run("Validate rad recipe register", func(t *testing.T) { + output, err := cli.RecipeRegister(ctx, envName, recipeName, templateKindBicep, recipeTemplate, resourceType, false) + require.NoError(t, err) + require.Contains(t, output, "Successfully linked recipe") + //}) - t.Run("Validate rad recipe show", func(t *testing.T) { - output, err := cli.RecipeShow(ctx, envName, bicepRecipe, resourceType) - require.NoError(t, err) - require.Contains(t, output, bicepRecipe) - require.Contains(t, output, bicepRecipeTemplate) - require.Contains(t, output, resourceType) - require.Contains(t, output, "redisName") - require.Contains(t, output, "string") - }) + //t.Run("Validate rad recipe register with insecure registry", func(t *testing.T) { + output, err = cli.RecipeRegister(ctx, envName, recipeName, templateKindBicep, recipeTemplate, resourceType, true) + require.NoError(t, err) + require.Contains(t, output, "Successfully linked recipe") + //}) - t.Run("Validate rad recipe show - terraform recipe", func(t *testing.T) { - showRecipeName := "redistesttf" - moduleServer := strings.TrimPrefix(testutil.GetTerraformRecipeModuleServerURL(), "moduleServer=") - showRecipeTemplate := fmt.Sprintf("%s/kubernetes-redis.zip//modules", moduleServer) - showRecipeResourceType := "Applications.Datastores/redisCaches" - output, err := cli.RecipeRegister(ctx, envName, showRecipeName, "terraform", showRecipeTemplate, showRecipeResourceType, false) - require.NoError(t, err) - require.Contains(t, output, "Successfully linked recipe") - output, err = cli.RecipeShow(ctx, envName, showRecipeName, showRecipeResourceType) - require.NoError(t, err) - require.Contains(t, output, showRecipeName) - require.Contains(t, output, showRecipeTemplate) - require.Contains(t, output, showRecipeResourceType) - require.Contains(t, output, "redis_cache_name") - require.Contains(t, output, "string") - }) + //t.Run("Validate rad recipe list", func(t *testing.T) { + output, err = cli.RecipeList(ctx, envName) + require.NoError(t, err) + require.Regexp(t, bicepRecipe, output) + require.Regexp(t, terraformRecipe, output) + require.Regexp(t, recipeName, output) + require.Regexp(t, resourceType, output) + require.Regexp(t, bicepRecipeTemplate, output) + require.Regexp(t, terraformRecipeTemplate, output) + require.Regexp(t, recipeTemplate, output) + require.Regexp(t, templateKindBicep, output) + require.Regexp(t, templateKindTerraform, output) + //}) + + // t.Run("Validate rad recipe unregister", func(t *testing.T) { + output, err = cli.RecipeUnregister(ctx, envName, recipeName, resourceType) + require.NoError(t, err) + require.Contains(t, output, "Successfully unregistered recipe") + // }) - t.Run("Validate `rad bicep publish` is publishing the file to the given target", func(t *testing.T) { - output, err := cli.BicepPublish(ctx, file, target) - require.NoError(t, err) - require.Contains(t, output, "Successfully published") - }) + // t.Run("Validate rad recipe show", func(t *testing.T) { + output, err = cli.RecipeShow(ctx, envName, bicepRecipe, resourceType) + require.NoError(t, err) + require.Contains(t, output, bicepRecipe) + require.Contains(t, output, bicepRecipeTemplate) + require.Contains(t, output, resourceType) + require.Contains(t, output, "redisName") + require.Contains(t, output, "string") + // }) + + // t.Run("Validate rad recipe show - terraform recipe", func(t *testing.T) { + showRecipeName := "redistesttf" + moduleServer := strings.TrimPrefix(testutil.GetTerraformRecipeModuleServerURL(), "moduleServer=") + showRecipeTemplate := fmt.Sprintf("%s/kubernetes-redis.zip//modules", moduleServer) + showRecipeResourceType := "Applications.Datastores/redisCaches" + output, err = cli.RecipeRegister(ctx, envName, showRecipeName, "terraform", showRecipeTemplate, showRecipeResourceType, false) + require.NoError(t, err) + require.Contains(t, output, "Successfully linked recipe") + output, err = cli.RecipeShow(ctx, envName, showRecipeName, showRecipeResourceType) + require.NoError(t, err) + require.Contains(t, output, showRecipeName) + require.Contains(t, output, showRecipeTemplate) + require.Contains(t, output, showRecipeResourceType) + require.Contains(t, output, "redis_cache_name") + require.Contains(t, output, "string") + // }) + + // t.Run("Validate `rad bicep publish` is publishing the file to the given target", func(t *testing.T) { + output, err = cli.BicepPublish(ctx, file, target) + require.NoError(t, err) + require.Contains(t, output, "Successfully published") + // }) - t.Run("Validate rad recipe register with recipe name conflicting with existing recipe", func(t *testing.T) { - output, err := cli.RecipeRegister(ctx, envName, bicepRecipe, templateKindBicep, recipeTemplate, resourceType, false) - require.Contains(t, output, "Successfully linked recipe") - require.NoError(t, err) - output, err = cli.RecipeList(ctx, envName) - require.NoError(t, err) - require.Regexp(t, recipeTemplate, output) - }) + // t.Run("Validate rad recipe register with recipe name conflicting with existing recipe", func(t *testing.T) { + output, err = cli.RecipeRegister(ctx, envName, bicepRecipe, templateKindBicep, recipeTemplate, resourceType, false) + require.Contains(t, output, "Successfully linked recipe") + require.NoError(t, err) + output, err = cli.RecipeList(ctx, envName) + require.NoError(t, err) + require.Regexp(t, recipeTemplate, output) + //}) } -func verifyCLIBasics(ctx context.Context, t *testing.T, test shared.RPTest) { +func verifyCLIBasics(ctx context.Context, t retry.TestingTB, test shared.RPTest) { options := shared.NewRPTestOptions(t) cli := radcli.NewCLI(t, options.ConfigFilePath) appName := test.Name @@ -167,95 +168,95 @@ func verifyCLIBasics(ctx context.Context, t *testing.T, test shared.RPTest) { scope, err := resources.ParseScope(options.Workspace.Scope) require.NoError(t, err) - t.Run("Validate rad application show", func(t *testing.T) { - actualOutput, err := cli.ApplicationShow(ctx, appName) - require.NoError(t, err) + //t.Run("Validate rad application show", func(t *testing.T) { + actualOutput, err := cli.ApplicationShow(ctx, appName) + require.NoError(t, err) - lines := strings.Split(actualOutput, "\n") - require.GreaterOrEqual(t, len(lines), 2, "Actual output should have 2 lines") + lines := strings.Split(actualOutput, "\n") + require.GreaterOrEqual(t, len(lines), 2, "Actual output should have 2 lines") - headers := strings.Fields(lines[0]) - require.Equal(t, "RESOURCE", headers[0], "First header should be RESOURCE") - require.Equal(t, "TYPE", headers[1], "Second header should be TYPE") - require.Equal(t, "GROUP", headers[2], "Third header should be GROUP") - require.Equal(t, "STATE", headers[3], "Fourth header should be STATE") + headers := strings.Fields(lines[0]) + require.Equal(t, "RESOURCE", headers[0], "First header should be RESOURCE") + require.Equal(t, "TYPE", headers[1], "Second header should be TYPE") + require.Equal(t, "GROUP", headers[2], "Third header should be GROUP") + require.Equal(t, "STATE", headers[3], "Fourth header should be STATE") - values := strings.Fields(lines[1]) - require.Equal(t, appName, values[0], "First value should be %s", appName) - require.Equal(t, "Applications.Core/applications", values[1], "Second value should be Applications.Core/applications") - require.Equal(t, scope.Name(), values[2], "Third value should be %s", scope.Name()) - require.Equal(t, "Succeeded", values[3], "Fourth value should be Succeeded") - }) + values := strings.Fields(lines[1]) + require.Equal(t, appName, values[0], "First value should be %s", appName) + require.Equal(t, "Applications.Core/applications", values[1], "Second value should be Applications.Core/applications") + require.Equal(t, scope.Name(), values[2], "Third value should be %s", scope.Name()) + require.Equal(t, "Succeeded", values[3], "Fourth value should be Succeeded") + //}) - t.Run("Validate rad resource list", func(t *testing.T) { - output, err := cli.ResourceList(ctx, appName) - require.NoError(t, err) - - // Resource ordering can vary so we don't assert exact output. - if strings.EqualFold(appName, "kubernetes-cli") { - require.Regexp(t, `containerA`, output) - require.Regexp(t, `containerB`, output) - } else { - require.Regexp(t, `containerA-json`, output) - require.Regexp(t, `containerB-json`, output) - } - }) + //t.Run("Validate rad resource list", func(t *testing.T) { + output, err := cli.ResourceList(ctx, appName) + require.NoError(t, err) - t.Run("Validate rad resource show", func(t *testing.T) { - actualOutput, err := cli.ResourceShow(ctx, "containers", containerName) - require.NoError(t, err) + // Resource ordering can vary so we don't assert exact output. + if strings.EqualFold(appName, "kubernetes-cli") { + require.Regexp(t, `containerA`, output) + require.Regexp(t, `containerB`, output) + } else { + require.Regexp(t, `containerA-json`, output) + require.Regexp(t, `containerB-json`, output) + } + //}) - lines := strings.Split(actualOutput, "\n") - require.GreaterOrEqual(t, len(lines), 2, "Actual output should have 2 lines") + //t.Run("Validate rad resource show", func(t *testing.T) { + actualOutput, err = cli.ResourceShow(ctx, "containers", containerName) + require.NoError(t, err) - headers := strings.Fields(lines[0]) - require.Equal(t, "RESOURCE", headers[0], "First header should be RESOURCE") - require.Equal(t, "TYPE", headers[1], "Second header should be TYPE") - require.Equal(t, "GROUP", headers[2], "Third header should be GROUP") - require.Equal(t, "STATE", headers[3], "Fourth header should be STATE") + lines = strings.Split(actualOutput, "\n") + require.GreaterOrEqual(t, len(lines), 2, "Actual output should have 2 lines") - values := strings.Fields(lines[1]) - require.Equal(t, containerName, values[0], "First value should be %s", containerName) - require.Equal(t, "Applications.Core/containers", values[1], "Second value should be Applications.Core/applications") - require.Equal(t, scope.Name(), values[2], "Third value should be %s", scope.Name()) - require.Equal(t, "Succeeded", values[3], "Fourth value should be Succeeded") - }) + headers = strings.Fields(lines[0]) + require.Equal(t, "RESOURCE", headers[0], "First header should be RESOURCE") + require.Equal(t, "TYPE", headers[1], "Second header should be TYPE") + require.Equal(t, "GROUP", headers[2], "Third header should be GROUP") + require.Equal(t, "STATE", headers[3], "Fourth header should be STATE") - t.Run("Validate rad resoure logs containers", func(t *testing.T) { - output, err := cli.ResourceLogs(ctx, appName, containerName) - require.NoError(t, err) + values = strings.Fields(lines[1]) + require.Equal(t, containerName, values[0], "First value should be %s", containerName) + require.Equal(t, "Applications.Core/containers", values[1], "Second value should be Applications.Core/applications") + require.Equal(t, scope.Name(), values[2], "Third value should be %s", scope.Name()) + require.Equal(t, "Succeeded", values[3], "Fourth value should be Succeeded") + //}) - // We don't want to be too fragile so we're not validating the logs in depth - require.Contains(t, output, "Server running at http://localhost:3000") - }) + //t.Run("Validate rad resoure logs containers", func(t *testing.T) { + output, err = cli.ResourceLogs(ctx, appName, containerName) + require.NoError(t, err) + + // We don't want to be too fragile so we're not validating the logs in depth + require.Contains(t, output, "Server running at http://localhost:3000") + //}) - t.Run("Validate rad resource expose Container", func(t *testing.T) { - port, err := GetAvailablePort() - require.NoError(t, err) + //t.Run("Validate rad resource expose Container", func(t *testing.T) { + port, err := GetAvailablePort() + require.NoError(t, err) - // We open a local port-forward and then make a request to it. - child, cancel := context.WithCancel(ctx) + // We open a local port-forward and then make a request to it. + child, cancel := context.WithCancel(ctx) - done := make(chan error) - go func() { - output, err := cli.ResourceExpose(child, appName, containerName, port, 3000) - t.Logf("ResourceExpose - output: %s", output) - done <- err - }() + done := make(chan error) + go func() { + output, err := cli.ResourceExpose(child, appName, containerName, port, 3000) + t.Logf("ResourceExpose - output: %s", output) + done <- err + }() - callHealthEndpointOnLocalPort(t, retries, port) + callHealthEndpointOnLocalPort(t, retries, port) - cancel() - err = <-done + cancel() + err = <-done - // The error should be due to cancellation (we can canceled the command). - require.Equal(t, context.Canceled, err) - }) + // The error should be due to cancellation (we can canceled the command). + require.Equal(t, context.Canceled, err) + //}) } // callHealthEndpointOnLocalPort calls the magpie health endpoint '/healthz' with retries. It will fail the // test if the exceed the number of retries without success. -func callHealthEndpointOnLocalPort(t *testing.T, retries int, port int) { +func callHealthEndpointOnLocalPort(t retry.TestingTB, retries int, port int) { healthzURL := fmt.Sprintf("http://localhost:%d/healthz", port) retryClient := retryablehttp.NewClient() diff --git a/test/functional-portable/daprrp/noncloud/resources/common.go b/test/functional-portable/daprrp/noncloud/resources/common.go index 3d4b53d380..82125b286a 100644 --- a/test/functional-portable/daprrp/noncloud/resources/common.go +++ b/test/functional-portable/daprrp/noncloud/resources/common.go @@ -18,8 +18,8 @@ package resource_test import ( "context" - "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/pkg/cli/clients" "github.com/radius-project/radius/pkg/cli/clients_new/generated" "github.com/radius-project/radius/test/functional/shared" @@ -30,7 +30,7 @@ import ( "k8s.io/client-go/dynamic" ) -func verifyDaprComponentsDeleted(ctx context.Context, t *testing.T, test shared.RPTest, resourceType, resourceName, namespace string) { +func verifyDaprComponentsDeleted(ctx context.Context, t retry.TestingTB, test shared.RPTest, resourceType, resourceName, namespace string) { resource, err := test.Options.ManagementClient.ShowResource(ctx, resourceType, resourceName) require.Error(t, err) require.True(t, clients.Is404Error(err)) diff --git a/test/functional-portable/daprrp/noncloud/resources/dapr_pubsub_test.go b/test/functional-portable/daprrp/noncloud/resources/dapr_pubsub_test.go index 7641c5e4e3..e6f0d07de5 100644 --- a/test/functional-portable/daprrp/noncloud/resources/dapr_pubsub_test.go +++ b/test/functional-portable/daprrp/noncloud/resources/dapr_pubsub_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -72,7 +73,7 @@ func Test_DaprPubSubBroker_Manual(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/pubSubBrokers", "dpsb-manual", appNamespace) } @@ -126,7 +127,7 @@ func Test_DaprPubSubBroker_Recipe(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/pubSubBrokers", "dpsb-recipe", appNamespace) } diff --git a/test/functional-portable/daprrp/noncloud/resources/dapr_secretstore_test.go b/test/functional-portable/daprrp/noncloud/resources/dapr_secretstore_test.go index 342d6f6e72..c7abefd7f6 100644 --- a/test/functional-portable/daprrp/noncloud/resources/dapr_secretstore_test.go +++ b/test/functional-portable/daprrp/noncloud/resources/dapr_secretstore_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -68,7 +69,7 @@ func Test_DaprSecretStore_Manual(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/secretStores", "gnrc-scs-manual", appNamespace) } @@ -117,7 +118,7 @@ func Test_DaprSecretStore_Recipe(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/secretStores", "gnrc-scs-recipe", appNamespace) } diff --git a/test/functional-portable/daprrp/noncloud/resources/dapr_statestore_test.go b/test/functional-portable/daprrp/noncloud/resources/dapr_statestore_test.go index 21bc7e2a75..78f82fc099 100644 --- a/test/functional-portable/daprrp/noncloud/resources/dapr_statestore_test.go +++ b/test/functional-portable/daprrp/noncloud/resources/dapr_statestore_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -74,7 +75,7 @@ func Test_DaprStateStore_Manual(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/stateStores", "dapr-sts-manual", appNamespace) } @@ -128,7 +129,7 @@ func Test_DaprStateStore_Recipe(t *testing.T) { test.RequiredFeatures = []shared.RequiredFeature{shared.FeatureDapr} - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { verifyDaprComponentsDeleted(ctx, t, test, "Applications.Dapr/stateStores", "dapr-sts-recipe", appNamespace) } diff --git a/test/functional-portable/datastoresrp/noncloud/resources/redis_test.go b/test/functional-portable/datastoresrp/noncloud/resources/redis_test.go index d62a62bf1c..aff8ceb658 100644 --- a/test/functional-portable/datastoresrp/noncloud/resources/redis_test.go +++ b/test/functional-portable/datastoresrp/noncloud/resources/redis_test.go @@ -21,6 +21,7 @@ import ( "strings" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -98,7 +99,7 @@ func Test_Redis_Recipe(t *testing.T) { }, }, SkipObjectValidation: true, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { redis, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Datastores/redisCaches", "rds-recipe") require.NoError(t, err) require.NotNil(t, redis) diff --git a/test/functional-portable/datastoresrp/noncloud/resources/simulated_environment_test.go b/test/functional-portable/datastoresrp/noncloud/resources/simulated_environment_test.go index cc2f6b7b4d..9f34e74f80 100644 --- a/test/functional-portable/datastoresrp/noncloud/resources/simulated_environment_test.go +++ b/test/functional-portable/datastoresrp/noncloud/resources/simulated_environment_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -65,7 +66,7 @@ func Test_Deployment_SimulatedEnv_BicepRecipe(t *testing.T) { }, SkipKubernetesOutputResourceValidation: true, SkipObjectValidation: true, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Get pods in app namespace label := fmt.Sprintf("radapp.io/application=%s", appName) pods, err := ct.Options.K8sClient.CoreV1().Pods(appNamespace).List(ctx, metav1.ListOptions{ diff --git a/test/functional-portable/samples/noncloud/tutorial_test.go b/test/functional-portable/samples/noncloud/tutorial_test.go index 25eb6a3e8d..902c6264fa 100644 --- a/test/functional-portable/samples/noncloud/tutorial_test.go +++ b/test/functional-portable/samples/noncloud/tutorial_test.go @@ -29,6 +29,7 @@ import ( "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/pkg/kubernetes" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" @@ -89,7 +90,7 @@ func Test_FirstApplicationSample(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Set up pod port-forwarding for the pod for i := 1; i <= retries; i++ { t.Logf("Setting up portforward (attempt %d/%d)", i, retries) @@ -120,7 +121,7 @@ func Test_FirstApplicationSample(t *testing.T) { test.Test(t) } -func testWithPortForward(t *testing.T, ctx context.Context, at shared.RPTest, namespace string, container string, remotePort int) error { +func testWithPortForward(t retry.TestingTB, ctx context.Context, at shared.RPTest, namespace string, container string, remotePort int) error { // stopChan will close the port-forward connection on close stopChan := make(chan struct{}) @@ -300,7 +301,7 @@ func testWithPortForward(t *testing.T, ctx context.Context, at shared.RPTest, na } } -func sendRequest(t *testing.T, req *http.Request, expectedStatusCode int) (*http.Response, error) { +func sendRequest(t retry.TestingTB, req *http.Request, expectedStatusCode int) (*http.Response, error) { res, err := http.DefaultClient.Do(req) if err != nil { return nil, err @@ -313,7 +314,7 @@ func sendRequest(t *testing.T, req *http.Request, expectedStatusCode int) (*http return res, nil } -func sendGetRequest(t *testing.T, hostname, baseURL, path string, expectedStatusCode int) (*http.Response, error) { +func sendGetRequest(t retry.TestingTB, hostname, baseURL, path string, expectedStatusCode int) (*http.Response, error) { req, err := http.NewRequest(http.MethodGet, getURLPath(baseURL, path), nil) if err != nil { return nil, err @@ -323,7 +324,7 @@ func sendGetRequest(t *testing.T, hostname, baseURL, path string, expectedStatus return sendRequest(t, req, expectedStatusCode) } -func sendPostRequest(t *testing.T, hostname, baseURL, path string, body *[]byte, expectedStatusCode int) (*http.Response, error) { +func sendPostRequest(t retry.TestingTB, hostname, baseURL, path string, body *[]byte, expectedStatusCode int) (*http.Response, error) { if body == nil { return nil, fmt.Errorf("body cannot be nil") } @@ -339,7 +340,7 @@ func sendPostRequest(t *testing.T, hostname, baseURL, path string, body *[]byte, return sendRequest(t, req, expectedStatusCode) } -func sendPutRequest(t *testing.T, hostname, baseURL, path string, body *[]byte, expectedStatusCode int) (*http.Response, error) { +func sendPutRequest(t retry.TestingTB, hostname, baseURL, path string, body *[]byte, expectedStatusCode int) (*http.Response, error) { if body == nil { return nil, fmt.Errorf("body cannot be nil") } @@ -355,7 +356,7 @@ func sendPutRequest(t *testing.T, hostname, baseURL, path string, body *[]byte, return sendRequest(t, req, expectedStatusCode) } -func sendDeleteRequest(t *testing.T, hostname, baseURL, path string, expectedStatusCode int) (*http.Response, error) { +func sendDeleteRequest(t retry.TestingTB, hostname, baseURL, path string, expectedStatusCode int) (*http.Response, error) { req, err := http.NewRequest(http.MethodDelete, getURLPath(baseURL, path), nil) if err != nil { return nil, err diff --git a/test/functional/shared/mechanics/mechanics_test.go b/test/functional/shared/mechanics/mechanics_test.go index 89355c11e6..a27a688747 100644 --- a/test/functional/shared/mechanics/mechanics_test.go +++ b/test/functional/shared/mechanics/mechanics_test.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/pkg/kubernetes" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" @@ -172,7 +173,7 @@ func Test_RedeployWithUpdatedResourceUpdatesResource(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { labelset := kubernetes.MakeSelectorLabels(name, "mechanicsd") deployments, err := test.Options.K8sClient.AppsV1().Deployments(appNamespace).List(context.Background(), metav1.ListOptions{ diff --git a/test/functional/shared/resources/application_environment_test.go b/test/functional/shared/resources/application_environment_test.go index 23ee2a1adb..2593ecee1a 100644 --- a/test/functional/shared/resources/application_environment_test.go +++ b/test/functional/shared/resources/application_environment_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/validation" @@ -48,7 +49,7 @@ func Test_ApplicationAndEnvironment(t *testing.T) { }, // Application and Environment should not render any K8s Objects directly K8sObjects: &validation.K8sObjectSet{}, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { expectedNS := []string{ "corerp-resources-app-env", "corerp-resources-app-env-env-corerp-resources-app-env-app", diff --git a/test/functional/shared/resources/application_test.go b/test/functional/shared/resources/application_test.go index 93fb90bc16..fcd5dfb201 100644 --- a/test/functional/shared/resources/application_test.go +++ b/test/functional/shared/resources/application_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -50,7 +51,7 @@ func Test_Application(t *testing.T) { }, // Application should not render any K8s Objects directly K8sObjects: &validation.K8sObjectSet{}, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { _, err := test.Options.K8sClient.CoreV1().Namespaces().Get(ctx, appNamespace, metav1.GetOptions{}) require.NoErrorf(t, err, "%s must be created", appNamespace) }, @@ -100,7 +101,7 @@ func Test_ApplicationGraph(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Verify the application graph options := shared.NewRPTestOptions(t) client := options.ManagementClient diff --git a/test/functional/shared/resources/container_runtimes_test.go b/test/functional/shared/resources/container_runtimes_test.go index b8c8389ca7..3b8f6f52a4 100644 --- a/test/functional/shared/resources/container_runtimes_test.go +++ b/test/functional/shared/resources/container_runtimes_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -64,7 +65,7 @@ func Test_Container_YAMLManifest(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { deploy, err := test.Options.K8sClient.AppsV1().Deployments(appNamespace).Get(ctx, "ctnr-manifest", metav1.GetOptions{}) require.NoError(t, err) require.Equal(t, "base-manifest-test", deploy.ObjectMeta.Annotations["source"]) @@ -130,7 +131,7 @@ func Test_Container_YAMLManifest_SideCar(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { deploy, err := test.Options.K8sClient.AppsV1().Deployments(appNamespace).Get(ctx, "ctnr-sidecar", metav1.GetOptions{}) require.NoError(t, err) @@ -176,7 +177,7 @@ func Test_Container_pod_patching(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { deploy, err := test.Options.K8sClient.AppsV1().Deployments(appNamespace).Get(ctx, "ctnr-podpatch", metav1.GetOptions{}) require.NoError(t, err) diff --git a/test/functional/shared/resources/container_test.go b/test/functional/shared/resources/container_test.go index dcd1de21ee..2effe6fdb9 100644 --- a/test/functional/shared/resources/container_test.go +++ b/test/functional/shared/resources/container_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -249,7 +250,7 @@ func Test_ContainerWithCommandAndArgs(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { label := fmt.Sprintf("radapp.io/application=%s", name) pods, err := test.Options.K8sClient.CoreV1().Pods(appNamespace).List(ctx, metav1.ListOptions{ LabelSelector: label, diff --git a/test/functional/shared/resources/container_versioning_test.go b/test/functional/shared/resources/container_versioning_test.go index 63786afcce..06f96335a1 100644 --- a/test/functional/shared/resources/container_versioning_test.go +++ b/test/functional/shared/resources/container_versioning_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -61,7 +62,7 @@ func Test_ContainerVersioning(t *testing.T) { }, }, SkipResourceDeletion: true, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { label := fmt.Sprintf("radapp.io/application=%s", name) secrets, err := test.Options.K8sClient.CoreV1().Secrets(appNamespace).List(ctx, metav1.ListOptions{ LabelSelector: label, @@ -92,7 +93,7 @@ func Test_ContainerVersioning(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { label := fmt.Sprintf("radapp.io/application=%s", name) secrets, err := test.Options.K8sClient.CoreV1().Secrets(appNamespace).List(ctx, metav1.ListOptions{ LabelSelector: label, diff --git a/test/functional/shared/resources/gateway_test.go b/test/functional/shared/resources/gateway_test.go index 7a64f51be0..a4cb94548d 100644 --- a/test/functional/shared/resources/gateway_test.go +++ b/test/functional/shared/resources/gateway_test.go @@ -27,6 +27,7 @@ import ( "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -90,7 +91,7 @@ func Test_GatewayDNS(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Get hostname from root HTTPProxy in application namespace metadata, err := testutil.GetHTTPProxyMetadata(ctx, ct.Options.Client, appNamespace, name) require.NoError(t, err) @@ -161,7 +162,7 @@ func Test_Gateway_SSLPassthrough(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Get hostname from root HTTPProxy in application namespace metadata, err := testutil.GetHTTPProxyMetadata(ctx, ct.Options.Client, appNamespace, name) require.NoError(t, err) @@ -233,7 +234,7 @@ func Test_Gateway_TLSTermination(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Get hostname from root HTTPProxy in application namespace metadata, err := testutil.GetHTTPProxyMetadata(ctx, ct.Options.Client, appNamespace, name) require.NoError(t, err) @@ -307,7 +308,7 @@ func Test_Gateway_Failure(t *testing.T) { test.Test(t) } -func testGatewayWithPortForward(t *testing.T, ctx context.Context, at shared.RPTest, hostname string, remotePort int, isHttps bool, tests []GatewayTestConfig) error { +func testGatewayWithPortForward(t retry.TestingTB, ctx context.Context, at shared.RPTest, hostname string, remotePort int, isHttps bool, tests []GatewayTestConfig) error { // stopChan will close the port-forward connection on close stopChan := make(chan struct{}) @@ -344,7 +345,7 @@ func testGatewayWithPortForward(t *testing.T, ctx context.Context, at shared.RPT } } -func testGatewayAvailability(t *testing.T, hostname, baseURL, path string, expectedStatusCode int, isHttps bool) error { +func testGatewayAvailability(t retry.TestingTB, hostname, baseURL, path string, expectedStatusCode int, isHttps bool) error { urlPath := strings.TrimSuffix(baseURL, "/") + "/" + strings.TrimPrefix(path, "/") req, err := http.NewRequest(http.MethodGet, urlPath, nil) if err != nil { diff --git a/test/functional/shared/resources/kubemetadata_cascade_test.go b/test/functional/shared/resources/kubemetadata_cascade_test.go index 06ee0cb625..a199e8a493 100644 --- a/test/functional/shared/resources/kubemetadata_cascade_test.go +++ b/test/functional/shared/resources/kubemetadata_cascade_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -95,7 +96,7 @@ func Test_KubeMetadataCascade(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { // Verify pod labels and annotations label := fmt.Sprintf("radapp.io/application=%s", name) pods, err := test.Options.K8sClient.CoreV1().Pods(appNamespace).List(ctx, metav1.ListOptions{ diff --git a/test/functional/shared/resources/kubemetadata_container_test.go b/test/functional/shared/resources/kubemetadata_container_test.go index d1461783fe..829f78bd8d 100644 --- a/test/functional/shared/resources/kubemetadata_container_test.go +++ b/test/functional/shared/resources/kubemetadata_container_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -71,7 +72,7 @@ func Test_KubeMetadataContainer(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { // Verify pod labels and annotations label := fmt.Sprintf("radapp.io/application=%s", name) pods, err := test.Options.K8sClient.CoreV1().Pods(appNamespace).List(ctx, metav1.ListOptions{ diff --git a/test/functional/shared/resources/kubemetadata_gateway_test.go b/test/functional/shared/resources/kubemetadata_gateway_test.go index 7409fc4975..89fdb712c0 100644 --- a/test/functional/shared/resources/kubemetadata_gateway_test.go +++ b/test/functional/shared/resources/kubemetadata_gateway_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -73,13 +74,13 @@ func Test_Gateway_KubernetesMetadata(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Check labels and annotations t.Logf("Checking label, annotation values in HTTPProxy resources") httpproxies, err := testutil.GetHTTPProxyList(ctx, ct.Options.Client, appNamespace, name) require.NoError(t, err) for _, httpproxy := range httpproxies.Items { - expectedLabels := getExpectedLabels(t, httpproxy.Name) + expectedLabels := getExpectedLabels(httpproxy.Name) require.Truef(t, testutil.IsMapSubSet(expectedLabels, httpproxy.Labels), "labels in httpproxy %v do not match expected values : ", httpproxy.Name) require.Truef(t, testutil.IsMapSubSet(expectedAnnotations, httpproxy.Annotations), "annotations in httpproxy %v do not match expected values", httpproxy.Name) } @@ -91,7 +92,7 @@ func Test_Gateway_KubernetesMetadata(t *testing.T) { } // getExpectedLabels returns the expected labels for the given resource name -func getExpectedLabels(t *testing.T, resourceName string) map[string]string { +func getExpectedLabels(resourceName string) map[string]string { return map[string]string{ "app.kubernetes.io/managed-by": "radius-rp", "app.kubernetes.io/name": resourceName, diff --git a/test/functional/shared/resources/kubemetadata_httproute_test.go b/test/functional/shared/resources/kubemetadata_httproute_test.go index 3b9df23c26..67c0dfae10 100644 --- a/test/functional/shared/resources/kubemetadata_httproute_test.go +++ b/test/functional/shared/resources/kubemetadata_httproute_test.go @@ -20,6 +20,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -73,7 +74,7 @@ func Test_KubeMetadataHTTPRoute(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { // Verify service labels and annotations service, err := test.Options.K8sClient.CoreV1().Services(appNamespace).Get(ctx, "ctnr-rte-kme-ctnr", metav1.GetOptions{}) diff --git a/test/functional/shared/resources/recipe_bicep_test.go b/test/functional/shared/resources/recipe_bicep_test.go index b7afaacc69..2d9e2e16ac 100644 --- a/test/functional/shared/resources/recipe_bicep_test.go +++ b/test/functional/shared/resources/recipe_bicep_test.go @@ -23,6 +23,7 @@ import ( "strings" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/pkg/recipes" "github.com/radius-project/radius/pkg/ucp/resources" "github.com/radius-project/radius/test/functional/shared" @@ -84,7 +85,7 @@ func Test_BicepRecipe_ParametersAndOutputs(t *testing.T) { }, }, K8sObjects: &validation.K8sObjectSet{}, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resource, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", name) require.NoError(t, err) @@ -138,7 +139,7 @@ func Test_BicepRecipe_ContextParameter(t *testing.T) { }, }, K8sObjects: &validation.K8sObjectSet{}, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resource, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", name) require.NoError(t, err) @@ -238,7 +239,7 @@ func Test_BicepRecipe_ResourceCreation(t *testing.T) { // Trying to delete the resources can cause multiple concurrent delete requests. // This currently fails. SkipResourceDeletion: true, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resource, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", name) require.NoError(t, err) diff --git a/test/functional/shared/resources/recipe_terraform_test.go b/test/functional/shared/resources/recipe_terraform_test.go index ec02155b16..707aa8472d 100644 --- a/test/functional/shared/resources/recipe_terraform_test.go +++ b/test/functional/shared/resources/recipe_terraform_test.go @@ -32,6 +32,7 @@ import ( "strings" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -102,7 +103,7 @@ func Test_TerraformRecipe_KubernetesRedis(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { secret, err := test.Options.K8sClient.CoreV1().Secrets(secretNamespace). Get(ctx, secretPrefix+secretSuffix, metav1.GetOptions{}) require.NoError(t, err) @@ -129,7 +130,7 @@ func Test_TerraformRecipe_KubernetesRedis(t *testing.T) { }, }) - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resourceID := "/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/" + name testSecretDeletion(t, ctx, test, appName, envName, resourceID) } @@ -175,7 +176,7 @@ func Test_TerraformRecipe_Context(t *testing.T) { }, }, }, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { // `k8ssecret-context` recipe should have created a secret with the populated recipe context. s, err := test.Options.K8sClient.CoreV1().Secrets(appNamespace).Get(ctx, name, metav1.GetOptions{}) require.NoError(t, err) @@ -222,7 +223,7 @@ func Test_TerraformRecipe_Context(t *testing.T) { }, }) - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resourceID := "/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/" + name testSecretDeletion(t, ctx, test, name, name, resourceID) } @@ -258,7 +259,7 @@ func Test_TerraformRecipe_AzureStorage(t *testing.T) { }, }, SkipObjectValidation: true, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resourceID := "/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/" + name secretSuffix, err := getSecretSuffix(resourceID, envName, appName) require.NoError(t, err) @@ -272,7 +273,7 @@ func Test_TerraformRecipe_AzureStorage(t *testing.T) { }, }) - test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + test.PostDeleteVerify = func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resourceID := "/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/" + name testSecretDeletion(t, ctx, test, appName, envName, resourceID) } @@ -327,7 +328,7 @@ func Test_TerraformRecipe_ParametersAndOutputs(t *testing.T) { }, }, K8sObjects: &validation.K8sObjectSet{}, - PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, test shared.RPTest) { resource, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", name) require.NoError(t, err) @@ -394,7 +395,7 @@ func Test_TerraformRecipe_WrongOutput(t *testing.T) { test.Test(t) } -func testSecretDeletion(t *testing.T, ctx context.Context, test shared.RPTest, appName, envName, resourceID string) { +func testSecretDeletion(t retry.TestingTB, ctx context.Context, test shared.RPTest, appName, envName, resourceID string) { secretSuffix, err := getSecretSuffix(resourceID, envName, appName) require.NoError(t, err) diff --git a/test/functional/shared/resources/simulated_environment_test.go b/test/functional/shared/resources/simulated_environment_test.go index b98a79e81a..e2e8199724 100644 --- a/test/functional/shared/resources/simulated_environment_test.go +++ b/test/functional/shared/resources/simulated_environment_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test/functional/shared" "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testutil" @@ -72,7 +73,7 @@ func Test_Deployment_SimulatedEnv(t *testing.T) { }, SkipKubernetesOutputResourceValidation: true, SkipObjectValidation: true, - PostStepVerify: func(ctx context.Context, t *testing.T, ct shared.RPTest) { + PostStepVerify: func(ctx context.Context, t retry.TestingTB, ct shared.RPTest) { // Get pods in app namespace label := fmt.Sprintf("radapp.io/application=%s", name) pods, err := ct.Options.K8sClient.CoreV1().Pods(appNamespace).List(ctx, metav1.ListOptions{ diff --git a/test/functional/shared/rptest.go b/test/functional/shared/rptest.go index 427fa70219..4b45184ddc 100644 --- a/test/functional/shared/rptest.go +++ b/test/functional/shared/rptest.go @@ -38,6 +38,8 @@ import ( "github.com/radius-project/radius/test/step" "github.com/radius-project/radius/test/testcontext" "github.com/radius-project/radius/test/validation" + + "github.com/hashicorp/consul/sdk/testutil/retry" ) var radiusControllerLogSync sync.Once @@ -94,7 +96,7 @@ type TestStep struct { K8sOutputResources []unstructured.Unstructured K8sObjects *validation.K8sObjectSet AWSResources *validation.AWSResourceSet - PostStepVerify func(ctx context.Context, t *testing.T, ct RPTest) + PostStepVerify func(ctx context.Context, t retry.TestingTB, ct RPTest) SkipKubernetesOutputResourceValidation bool SkipObjectValidation bool SkipResourceDeletion bool @@ -106,7 +108,7 @@ type RPTest struct { Description string InitialResources []unstructured.Unstructured Steps []TestStep - PostDeleteVerify func(ctx context.Context, t *testing.T, ct RPTest) + PostDeleteVerify func(ctx context.Context, t retry.TestingTB, ct RPTest) // RequiredFeatures specifies the optional features that are required // for this test to run. @@ -303,56 +305,59 @@ func (ct RPTest) Test(t *testing.T) { success := true for i, step := range ct.Steps { success = t.Run(step.Executor.GetDescription(), func(t *testing.T) { - defer ct.CleanUpExtensionResources(step.K8sOutputResources) if !success { t.Skip("skipping due to previous step failure") return } - t.Logf("running step %d of %d: %s", i, len(ct.Steps), step.Executor.GetDescription()) - step.Executor.Execute(ctx, t, ct.Options.TestOptions) - t.Logf("finished running step %d of %d: %s", i, len(ct.Steps), step.Executor.GetDescription()) - - if step.SkipKubernetesOutputResourceValidation { - t.Logf("skipping validation of resources...") - } else if step.RPResources == nil || len(step.RPResources.Resources) == 0 { - require.Fail(t, "no resource set was specified and SkipKubernetesOutputResourceValidation == false, either specify a resource set or set SkipResourceValidation = true ") - } else { - // Validate that all expected output resources are created - t.Logf("validating output resources for %s", step.Executor.GetDescription()) - validation.ValidateRPResources(ctx, t, step.RPResources, ct.Options.ManagementClient) - t.Logf("finished validating output resources for %s", step.Executor.GetDescription()) - } + retry.Run(t, func(r *retry.R) { + defer ct.CleanUpExtensionResources(step.K8sOutputResources) - // Validate AWS resources if specified - if step.AWSResources == nil || len(step.AWSResources.Resources) == 0 { - t.Logf("no AWS resource set was specified, skipping validation") - } else { - // Validate that all expected output resources are created - t.Logf("validating output resources for %s", step.Executor.GetDescription()) - // Use the AWS CloudControl.Get method to validate that the resources are created - validation.ValidateAWSResources(ctx, t, step.AWSResources, ct.Options.AWSClient) - t.Logf("finished validating output resources for %s", step.Executor.GetDescription()) - } + r.Logf("running step %d of %d: %s", i, len(ct.Steps), step.Executor.GetDescription()) + step.Executor.Execute(ctx, r, ct.Options.TestOptions) + r.Logf("finished running step %d of %d: %s", i, len(ct.Steps), step.Executor.GetDescription()) - if step.SkipObjectValidation { - t.Logf("skipping validation of objects...") - } else if step.K8sObjects == nil && len(step.K8sOutputResources) == 0 { - require.Fail(t, "no objects specified and SkipObjectValidation == false, either specify an object set or set SkipObjectValidation = true ") - } else { - if step.K8sObjects != nil { - t.Logf("validating creation of objects for %s", step.Executor.GetDescription()) - validation.ValidateObjectsRunning(ctx, t, ct.Options.K8sClient, ct.Options.DynamicClient, *step.K8sObjects) - t.Logf("finished validating creation of objects for %s", step.Executor.GetDescription()) + if step.SkipKubernetesOutputResourceValidation { + r.Logf("skipping validation of resources...") + } else if step.RPResources == nil || len(step.RPResources.Resources) == 0 { + require.Fail(r, "no resource set was specified and SkipKubernetesOutputResourceValidation == false, either specify a resource set or set SkipResourceValidation = true ") + } else { + // Validate that all expected output resources are created + r.Logf("validating output resources for %s", step.Executor.GetDescription()) + validation.ValidateRPResources(ctx, r, step.RPResources, ct.Options.ManagementClient) + r.Logf("finished validating output resources for %s", step.Executor.GetDescription()) } - } - // Custom verification is expected to use `t` to trigger its own assertions - if step.PostStepVerify != nil { - t.Logf("running post-deploy verification for %s", step.Executor.GetDescription()) - step.PostStepVerify(ctx, t, ct) - t.Logf("finished post-deploy verification for %s", step.Executor.GetDescription()) - } + // Validate AWS resources if specified + if step.AWSResources == nil || len(step.AWSResources.Resources) == 0 { + r.Logf("no AWS resource set was specified, skipping validation") + } else { + // Validate that all expected output resources are created + r.Logf("validating output resources for %s", step.Executor.GetDescription()) + // Use the AWS CloudControl.Get method to validate that the resources are created + validation.ValidateAWSResources(ctx, r, step.AWSResources, ct.Options.AWSClient) + r.Logf("finished validating output resources for %s", step.Executor.GetDescription()) + } + + if step.SkipObjectValidation { + r.Logf("skipping validation of objects...") + } else if step.K8sObjects == nil && len(step.K8sOutputResources) == 0 { + require.Fail(r, "no objects specified and SkipObjectValidation == false, either specify an object set or set SkipObjectValidation = true ") + } else { + if step.K8sObjects != nil { + r.Logf("validating creation of objects for %s", step.Executor.GetDescription()) + validation.ValidateObjectsRunning(ctx, r, ct.Options.K8sClient, ct.Options.DynamicClient, *step.K8sObjects) + r.Logf("finished validating creation of objects for %s", step.Executor.GetDescription()) + } + } + + // Custom verification is expected to use `t` to trigger its own assertions + if step.PostStepVerify != nil { + r.Logf("running post-deploy verification for %s", step.Executor.GetDescription()) + step.PostStepVerify(ctx, r, ct) + r.Logf("finished post-deploy verification for %s", step.Executor.GetDescription()) + } + }, retry.WithRetryer(&retry.Counter{Count: 2, Wait: 15 * time.Second})) }) } @@ -360,71 +365,77 @@ func (ct RPTest) Test(t *testing.T) { // Cleanup code here will run regardless of pass/fail of subtests for _, step := range ct.Steps { - // Delete AWS resources if they were created. This delete logic is here because deleting a Radius Application - // will not delete the AWS resources that were created as part of the Bicep deployment. - if step.AWSResources != nil && len(step.AWSResources.Resources) > 0 { - for _, resource := range step.AWSResources.Resources { - if !resource.SkipDeletion { - t.Logf("deleting %s", resource.Name) - - // Use the AWS CloudControl.Delete method to delete the resource - err := validation.DeleteAWSResource(ctx, &resource, ct.Options.AWSClient) - if err != nil { - t.Logf("failed to delete %s: %s", resource.Name, err) - } + retry.Run(t, func(r *retry.R) { + // Delete AWS resources if they were created. This delete logic is here because deleting a Radius Application + // will not delete the AWS resources that were created as part of the Bicep deployment. + if step.AWSResources != nil && len(step.AWSResources.Resources) > 0 { + for _, resource := range step.AWSResources.Resources { + if !resource.SkipDeletion { + r.Logf("deleting %s", resource.Name) + + // Use the AWS CloudControl.Delete method to delete the resource + err := validation.DeleteAWSResource(ctx, &resource, ct.Options.AWSClient) + if err != nil { + r.Logf("failed to delete %s: %s", resource.Name, err) + } - // Ensure that the resource is deleted with retries - notFound := false - for attempt := 1; attempt <= AWSDeletionRetryLimit; attempt++ { - t.Logf("validating deletion of AWS resource for %s (attempt %d/%d)", ct.Description, attempt, AWSDeletionRetryLimit) - - // Use AWS CloudControl.Get method to validate that the resource is deleted - notFound, err = validation.IsAWSResourceNotFound(ctx, &resource, ct.Options.AWSClient) - - if notFound { - t.Logf("AWS resource %s to be deleted was not found", resource.Identifier) - break - } else if err != nil { - t.Logf("checking existence of resource %s failed with err: %s", resource.Name, err) - break - } else { - // Wait for 10 seconds - time.Sleep(10 * time.Second) + // Ensure that the resource is deleted with retries + notFound := false + for attempt := 1; attempt <= AWSDeletionRetryLimit; attempt++ { + r.Logf("validating deletion of AWS resource for %s (attempt %d/%d)", ct.Description, attempt, AWSDeletionRetryLimit) + + // Use AWS CloudControl.Get method to validate that the resource is deleted + notFound, err = validation.IsAWSResourceNotFound(ctx, &resource, ct.Options.AWSClient) + + if notFound { + r.Logf("AWS resource %s to be deleted was not found", resource.Identifier) + break + } else if err != nil { + r.Logf("checking existence of resource %s failed with err: %s", resource.Name, err) + break + } else { + // Wait for 10 seconds + time.Sleep(30 * time.Second) + } } - } - require.Truef(t, notFound, "AWS resource %s was present, should be not found", resource.Identifier) - t.Logf("finished validation of deletion of AWS resource %s for %s", resource.Name, ct.Description) - } else { - t.Logf("skipping deletion of %s", resource.Name) + require.Truef(t, notFound, "AWS resource %s was present, should be not found", resource.Identifier) + r.Logf("finished validation of deletion of AWS resource %s for %s", resource.Name, ct.Description) + } else { + r.Logf("skipping deletion of %s", resource.Name) + } } } - } - if (step.RPResources == nil && step.SkipKubernetesOutputResourceValidation) || step.SkipResourceDeletion { - continue - } + if (step.RPResources == nil && step.SkipKubernetesOutputResourceValidation) || step.SkipResourceDeletion { + return + } + + for _, resource := range step.RPResources.Resources { + r.Logf("deleting %s", resource.Name) + err := validation.DeleteRPResource(ctx, r, cli, ct.Options.ManagementClient, resource) + require.NoErrorf(r, err, "failed to delete %s", resource.Name) + r.Logf("finished deleting %s", ct.Description) - for _, resource := range step.RPResources.Resources { - t.Logf("deleting %s", resource.Name) - err := validation.DeleteRPResource(ctx, t, cli, ct.Options.ManagementClient, resource) - require.NoErrorf(t, err, "failed to delete %s", resource.Name) - t.Logf("finished deleting %s", ct.Description) - - if step.SkipObjectValidation { - t.Logf("skipping validation of deletion of pods...") - } else { - t.Logf("validating deletion of pods for %s", ct.Description) - validation.ValidateNoPodsInApplication(ctx, t, ct.Options.K8sClient, TestNamespace, ct.Name) - t.Logf("finished validation of deletion of pods for %s", ct.Description) + if step.SkipObjectValidation { + r.Logf("skipping validation of deletion of pods...") + } else { + r.Logf("validating deletion of pods for %s", ct.Description) + validation.ValidateNoPodsInApplication(ctx, r, ct.Options.K8sClient, TestNamespace, ct.Name) + r.Logf("finished validation of deletion of pods for %s", ct.Description) + } } - } + }, retry.WithRetryer(&retry.Counter{Count: 2, Wait: 15 * time.Second})) } // Custom verification is expected to use `t` to trigger its own assertions if ct.PostDeleteVerify != nil { t.Logf("running post-delete verification for %s", ct.Description) - ct.PostDeleteVerify(ctx, t, ct) + + retry.Run(t, func(r *retry.R) { + ct.PostDeleteVerify(ctx, r, ct) + }, retry.WithRetryer(&retry.Counter{Count: 2, Wait: 15 * time.Second})) + t.Logf("finished post-delete verification for %s", ct.Description) } diff --git a/test/functional/shared/test.go b/test/functional/shared/test.go index de9f1f0d97..86dc5739fd 100644 --- a/test/functional/shared/test.go +++ b/test/functional/shared/test.go @@ -18,9 +18,9 @@ package shared import ( "strings" - "testing" "github.com/aws/aws-sdk-go-v2/service/cloudcontrol" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" awsconfig "github.com/aws/aws-sdk-go-v2/config" @@ -39,7 +39,7 @@ import ( // NewRPTestOptions sets up the test environment by loading configs, creating a test context, creating an // ApplicationsManagementClient, creating an AWSCloudControlClient, and returning an RPTestOptions struct. -func NewRPTestOptions(t *testing.T) RPTestOptions { +func NewRPTestOptions(t retry.TestingTB) RPTestOptions { registry, tag := testutil.SetDefault() t.Logf("Using container registry: %s - set DOCKER_REGISTRY to override", registry) t.Logf("Using container tag: %s - set REL_VERSION to override", tag) diff --git a/test/options.go b/test/options.go index 2dc2ad2c55..8fa2f794ba 100644 --- a/test/options.go +++ b/test/options.go @@ -17,8 +17,7 @@ limitations under the License. package test import ( - "testing" - + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" "k8s.io/client-go/dynamic" k8s "k8s.io/client-go/kubernetes" @@ -38,7 +37,7 @@ type TestOptions struct { } // NewTestOptions creates a TestOptions struct with the necessary clients and configs for testing. -func NewTestOptions(t *testing.T) TestOptions { +func NewTestOptions(t retry.TestingTB) TestOptions { config, err := cli.LoadConfig("") require.NoError(t, err, "failed to read radius config") diff --git a/test/radcli/cli.go b/test/radcli/cli.go index 9556f75bf8..684f8cf9e3 100644 --- a/test/radcli/cli.go +++ b/test/radcli/cli.go @@ -25,9 +25,9 @@ import ( "os/exec" "path" "strings" - "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" v1 "github.com/radius-project/radius/pkg/armrpc/api/v1" ) @@ -36,13 +36,13 @@ const ( ) type CLI struct { - T *testing.T + T retry.TestingTB ConfigFilePath string WorkingDirectory string } // NewCLI creates a new CLI instance with the given testing.T and config file path. -func NewCLI(t *testing.T, configFilePath string) *CLI { +func NewCLI(t retry.TestingTB, configFilePath string) *CLI { return &CLI{ T: t, ConfigFilePath: configFilePath, diff --git a/test/step/deployerrorexecutor.go b/test/step/deployerrorexecutor.go index 0132c7c994..90e5817b68 100644 --- a/test/step/deployerrorexecutor.go +++ b/test/step/deployerrorexecutor.go @@ -24,6 +24,7 @@ import ( "strings" "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -40,7 +41,7 @@ type DeployErrorExecutor struct { Parameters []string // ValidateError is a function that can be used to validate the error when it occurs. - ValidateError func(*testing.T, *radcli.CLIError) + ValidateError func(retry.TestingTB, *radcli.CLIError) // Application sets the `--application` command-line parameter. This is needed in cases where // the application is not defined in bicep. @@ -64,7 +65,7 @@ type DeploymentErrorDetail struct { } // NewDeployErrorExecutor creates a new DeployErrorExecutor instance with the given template, error code and parameters. -func NewDeployErrorExecutor(template string, validateError func(*testing.T, *radcli.CLIError), parameters ...string) *DeployErrorExecutor { +func NewDeployErrorExecutor(template string, validateError func(retry.TestingTB, *radcli.CLIError), parameters ...string) *DeployErrorExecutor { return &DeployErrorExecutor{ Description: fmt.Sprintf("deploy %s", template), Template: template, @@ -91,7 +92,7 @@ func (d *DeployErrorExecutor) GetDescription() string { } // Execute deploys an application from a template file and checks that the deployment fails with the expected error code. -func (d *DeployErrorExecutor) Execute(ctx context.Context, t *testing.T, options test.TestOptions) { +func (d *DeployErrorExecutor) Execute(ctx context.Context, t retry.TestingTB, options test.TestOptions) { cwd, err := os.Getwd() require.NoError(t, err) @@ -152,8 +153,8 @@ func ValidateCode(code string) func(*testing.T, *radcli.CLIError) { } // ValidateSingleDetail reports success if the error code matches the expected code and the detail item is found in the error response.. -func ValidateSingleDetail(code string, detail DeploymentErrorDetail) func(*testing.T, *radcli.CLIError) { - return func(t *testing.T, err *radcli.CLIError) { +func ValidateSingleDetail(code string, detail DeploymentErrorDetail) func(retry.TestingTB, *radcli.CLIError) { + return func(t retry.TestingTB, err *radcli.CLIError) { require.Equal(t, code, err.ErrorResponse.Error.Code, "unexpected error code") for _, candidate := range err.ErrorResponse.Error.Details { if detail.Matches(candidate) { @@ -166,8 +167,8 @@ func ValidateSingleDetail(code string, detail DeploymentErrorDetail) func(*testi } // ValidateAnyDetails reports success if any of the provided error details are found in the error response. -func ValidateAnyDetails(code string, details []DeploymentErrorDetail) func(*testing.T, *radcli.CLIError) { - return func(t *testing.T, err *radcli.CLIError) { +func ValidateAnyDetails(code string, details []DeploymentErrorDetail) func(retry.TestingTB, *radcli.CLIError) { + return func(t retry.TestingTB, err *radcli.CLIError) { require.Equal(t, code, err.ErrorResponse.Error.Code, "unexpected error code") for _, detail := range details { for _, candidate := range err.ErrorResponse.Error.Details { @@ -182,8 +183,8 @@ func ValidateAnyDetails(code string, details []DeploymentErrorDetail) func(*test } // ValidateAllDetails reports success if all of the provided error details are found in the error response. -func ValidateAllDetails(code string, details []DeploymentErrorDetail) func(*testing.T, *radcli.CLIError) { - return func(t *testing.T, err *radcli.CLIError) { +func ValidateAllDetails(code string, details []DeploymentErrorDetail) func(retry.TestingTB, *radcli.CLIError) { + return func(t retry.TestingTB, err *radcli.CLIError) { require.Equal(t, code, err.ErrorResponse.Error.Code, "unexpected error code") for _, detail := range details { matched := false diff --git a/test/step/deployexecutor.go b/test/step/deployexecutor.go index b5e7377c02..483e21da14 100644 --- a/test/step/deployexecutor.go +++ b/test/step/deployexecutor.go @@ -21,8 +21,8 @@ import ( "fmt" "os" "path/filepath" - "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" "github.com/radius-project/radius/test" @@ -72,7 +72,7 @@ func (d *DeployExecutor) GetDescription() string { } // Execute deploys an application from a template file using the provided parameters and logs the deployment process. -func (d *DeployExecutor) Execute(ctx context.Context, t *testing.T, options test.TestOptions) { +func (d *DeployExecutor) Execute(ctx context.Context, t retry.TestingTB, options test.TestOptions) { cwd, err := os.Getwd() require.NoError(t, err) diff --git a/test/step/interface.go b/test/step/interface.go index a32f7268a6..f0928c38f7 100644 --- a/test/step/interface.go +++ b/test/step/interface.go @@ -18,12 +18,12 @@ package step import ( "context" - "testing" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/test" ) type Executor interface { GetDescription() string - Execute(ctx context.Context, t *testing.T, options test.TestOptions) + Execute(ctx context.Context, t retry.TestingTB, options test.TestOptions) } diff --git a/test/testcontext/testcontext.go b/test/testcontext/testcontext.go index 6f6a65a330..3415139cd9 100644 --- a/test/testcontext/testcontext.go +++ b/test/testcontext/testcontext.go @@ -23,10 +23,11 @@ import ( "github.com/go-logr/logr" "github.com/go-logr/logr/testr" + "github.com/hashicorp/consul/sdk/testutil/retry" ) // New creates a new context with test logger for testing. -func New(t *testing.T) context.Context { +func New(t retry.TestingTB) context.Context { ctx, _ := Wrap(t, context.Background()) return ctx } @@ -43,14 +44,19 @@ func NewWithDeadline(t *testing.T, duration time.Duration) (context.Context, con } // Wrap wraps a context with test logger for testing and returns the context with cancel function. -func Wrap(t *testing.T, ctx context.Context) (context.Context, context.CancelFunc) { +func Wrap(t retry.TestingTB, ctx context.Context) (context.Context, context.CancelFunc) { if ctx == nil { ctx = context.Background() } + tt, ok := t.(*testing.T) + if !ok { + return ctx, func() {} + } + // Setting verbosity so that everything gets logged. - ctx = logr.NewContext(ctx, testr.NewWithOptions(t, testr.Options{LogTimestamp: true, Verbosity: 10000})) - deadline, ok := t.Deadline() + ctx = logr.NewContext(ctx, testr.NewWithOptions(tt, testr.Options{LogTimestamp: true, Verbosity: 10000})) + deadline, ok := tt.Deadline() if ok { return context.WithDeadline(ctx, deadline) } else { diff --git a/test/testutil/testutil.go b/test/testutil/testutil.go index e76450326d..ec8d790f68 100644 --- a/test/testutil/testutil.go +++ b/test/testutil/testutil.go @@ -29,6 +29,7 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/testutil/retry" contourv1 "github.com/projectcontour/contour/apis/projectcontour/v1" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -183,14 +184,14 @@ func GetHTTPProxyList(ctx context.Context, client runtime_client.Client, namespa // ExposeIngress creates a port-forward session and sends the (assigned) local port to portChan. It exposes a pod // in the RadiusSystemNamespace with the selector "app.kubernetes.io/component=envoy" on the given remotePort // and returns the port number and an error if any. -func ExposeIngress(t *testing.T, ctx context.Context, client *k8s.Clientset, config *rest.Config, remotePort int, stopChan chan struct{}, portChan chan int, errorChan chan error) { +func ExposeIngress(t retry.TestingTB, ctx context.Context, client *k8s.Clientset, config *rest.Config, remotePort int, stopChan chan struct{}, portChan chan int, errorChan chan error) { selector := "app.kubernetes.io/component=envoy" ExposePod(t, ctx, client, config, RadiusSystemNamespace, selector, remotePort, stopChan, portChan, errorChan) } // ExposePod creates a port-forward session. It finds a pod matching the given selector, creates an API Server URL, // sets up a port-forwarder, and sends the assigned port to the portChan channel. -func ExposePod(t *testing.T, ctx context.Context, client *k8s.Clientset, config *rest.Config, namespace string, selector string, remotePort int, stopChan chan struct{}, portChan chan int, errorChan chan error) { +func ExposePod(t retry.TestingTB, ctx context.Context, client *k8s.Clientset, config *rest.Config, namespace string, selector string, remotePort int, stopChan chan struct{}, portChan chan int, errorChan chan error) { // Find matching pods pods, err := client.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{LabelSelector: selector, Limit: 1}) if err != nil { @@ -284,7 +285,7 @@ func IsMapNonIntersecting(notExpectedMap map[string]string, actualMap map[string } type TestWriter struct { - t *testing.T + t retry.TestingTB } // TestWriter.Write writes the given byte slice to the test log. @@ -295,7 +296,7 @@ func (tw TestWriter) Write(p []byte) (n int, err error) { // WriteBicepParameterFile writes a Bicep parameter file to a temporary file and returns the path to the file. // The temporary file will be removed when the test finishes. -func WriteBicepParameterFile(t *testing.T, data map[string]any) string { +func WriteBicepParameterFile(t retry.TestingTB, data map[string]any) string { file := filepath.Join(t.TempDir(), uuid.New().String()+".json") values := map[string]any{} diff --git a/test/validation/aws.go b/test/validation/aws.go index 267a05d8ba..ae11b4a60a 100644 --- a/test/validation/aws.go +++ b/test/validation/aws.go @@ -20,9 +20,9 @@ import ( "encoding/json" "fmt" "os" - "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/radius-project/radius/pkg/to" "github.com/aws/aws-sdk-go-v2/credentials" @@ -60,7 +60,7 @@ type AWSResourceSet struct { } // ValidateAWSResources checks that the expected AWS resources exist and have the expected properties. -func ValidateAWSResources(ctx context.Context, t *testing.T, expected *AWSResourceSet, client awsclient.AWSCloudControlClient) { +func ValidateAWSResources(ctx context.Context, t *retry.R, expected *AWSResourceSet, client awsclient.AWSCloudControlClient) { for _, resource := range expected.Resources { resourceType, err := GetResourceTypeName(ctx, &resource) require.NoError(t, err) @@ -181,7 +181,7 @@ func GetResourceTypeName(ctx context.Context, resource *AWSResource) (string, er } // assertFieldsArePresent ensures that all fields in actual exist and are equivalent in expected -func assertFieldsArePresent(t *testing.T, actual any, expected any) { +func assertFieldsArePresent(t *retry.R, actual any, expected any) { switch actual := actual.(type) { case map[string]any: if expectedMap, ok := expected.(map[string]any); ok { diff --git a/test/validation/k8s.go b/test/validation/k8s.go index e612b9553f..de2ebaabd2 100644 --- a/test/validation/k8s.go +++ b/test/validation/k8s.go @@ -24,6 +24,7 @@ import ( "testing" "time" + "github.com/hashicorp/consul/sdk/testutil/retry" kuberneteskeys "github.com/radius-project/radius/pkg/kubernetes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -309,7 +310,7 @@ func streamLogFile(ctx context.Context, podClient v1.PodInterface, pod corev1.Po } // ValidateObjectsRunning checks if the expected Kubernetes objects are running in the given namespace. -func ValidateObjectsRunning(ctx context.Context, t *testing.T, k8s *kubernetes.Clientset, dynamic dynamic.Interface, expected K8sObjectSet) { +func ValidateObjectsRunning(ctx context.Context, t retry.TestingTB, k8s *kubernetes.Clientset, dynamic dynamic.Interface, expected K8sObjectSet) { restMapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(k8s.DiscoveryClient)) for namespace, expectedObjects := range expected.Namespaces { log.Printf("validating objects in namespace %v", namespace) @@ -380,7 +381,7 @@ func ValidateObjectsRunning(ctx context.Context, t *testing.T, k8s *kubernetes.C // ValidateNoPodsInApplication checks if there are any pods in the given namespace for the given application and waits for // them to be deleted if found. -func ValidateNoPodsInApplication(ctx context.Context, t *testing.T, k8s *kubernetes.Clientset, namespace string, application string) { +func ValidateNoPodsInApplication(ctx context.Context, t retry.TestingTB, k8s *kubernetes.Clientset, namespace string, application string) { labelset := kuberneteskeys.MakeSelectorLabels(application, "") actualPods, err := k8s.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{ @@ -417,7 +418,7 @@ func ValidateNoPodsInApplication(ctx context.Context, t *testing.T, k8s *kuberne } } -func listPodsWithRetries(t *testing.T, k8s *kubernetes.Clientset, labelset map[string]string, namespace, application string) (*corev1.PodList, error) { +func listPodsWithRetries(t retry.TestingTB, k8s *kubernetes.Clientset, labelset map[string]string, namespace, application string) (*corev1.PodList, error) { // Need to retry because of AKS error: https://github.com/radius-project/radius/issues/2484 retries := 3 for i := 1; i <= retries; i++ { @@ -442,7 +443,7 @@ type PodMonitor struct { // PodMonitor ValidateRunning watches a pod for its status to become running and checks its readiness, retrying a few times // if the readiness check fails. If the pod enters a failing state, an error is returned. -func (pm PodMonitor) ValidateRunning(ctx context.Context, t *testing.T) { +func (pm PodMonitor) ValidateRunning(ctx context.Context, t retry.TestingTB) { if pm.Pod.Status.Phase == corev1.PodRunning { if checkReadiness(t, &pm.Pod) { return @@ -510,7 +511,7 @@ func (pm PodMonitor) ValidateRunning(ctx context.Context, t *testing.T) { } } -func checkReadiness(t *testing.T, pod *corev1.Pod) bool { +func checkReadiness(t retry.TestingTB, pod *corev1.Pod) bool { for _, condition := range pod.Status.Conditions { if condition.Type == corev1.ContainersReady && condition.Status == corev1.ConditionTrue { @@ -521,7 +522,7 @@ func checkReadiness(t *testing.T, pod *corev1.Pod) bool { return false } -func logPods(t *testing.T, pods []corev1.Pod) { +func logPods(t retry.TestingTB, pods []corev1.Pod) { t.Log("Found the following pods:") if len(pods) == 0 { t.Logf("(none)") @@ -532,7 +533,7 @@ func logPods(t *testing.T, pods []corev1.Pod) { } } -func matchesActualLabels(t *testing.T, expectedResources []K8sObject, actualResources []unstructured.Unstructured) bool { +func matchesActualLabels(t retry.TestingTB, expectedResources []K8sObject, actualResources []unstructured.Unstructured) bool { remaining := []K8sObject{} for _, expectedResource := range expectedResources { diff --git a/test/validation/shared.go b/test/validation/shared.go index f0636e1da4..10cbad2d1f 100644 --- a/test/validation/shared.go +++ b/test/validation/shared.go @@ -21,7 +21,6 @@ import ( "fmt" "net/http" "strings" - "testing" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/radius-project/radius/pkg/cli" @@ -31,7 +30,8 @@ import ( "github.com/stretchr/testify/require" "github.com/radius-project/radius/test/radcli" - "github.com/radius-project/radius/test/testcontext" + + "github.com/hashicorp/consul/sdk/testutil/retry" ) const ( @@ -72,7 +72,7 @@ type RPResourceSet struct { // DeleteRPResource deletes an environment or application resource depending on the type of the resource passed in, and // returns an error if one occurs. -func DeleteRPResource(ctx context.Context, t *testing.T, cli *radcli.CLI, client clients.ApplicationsManagementClient, resource RPResource) error { +func DeleteRPResource(ctx context.Context, t retry.TestingTB, cli *radcli.CLI, client clients.ApplicationsManagementClient, resource RPResource) error { if resource.Type == EnvironmentsResource { t.Logf("deleting environment: %s", resource.Name) @@ -103,7 +103,7 @@ func DeleteRPResource(ctx context.Context, t *testing.T, cli *radcli.CLI, client } // ValidateRPResources checks if the expected resources exist in the response and validates the output resources if present. -func ValidateRPResources(ctx context.Context, t *testing.T, expected *RPResourceSet, client clients.ApplicationsManagementClient) { +func ValidateRPResources(ctx context.Context, t retry.TestingTB, expected *RPResourceSet, client clients.ApplicationsManagementClient) { for _, expectedResource := range expected.Resources { if expectedResource.Type == EnvironmentsResource { envs, err := client.ListEnvironmentsInResourceGroup(ctx) @@ -174,8 +174,8 @@ func ValidateRPResources(ctx context.Context, t *testing.T, expected *RPResource } // AssertCredentialExists checks if the credential is registered in the workspace and returns a boolean value. -func AssertCredentialExists(t *testing.T, credential string) bool { - ctx := testcontext.New(t) +func AssertCredentialExists(t retry.TestingTB, credential string) bool { + ctx := context.Background() config, err := cli.LoadConfig("") require.NoError(t, err, "failed to read radius config")