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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 16 additions & 35 deletions test/functional-portable/cli/noncloud/env_deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,41 +38,22 @@ func Test_DeployEnvironmentTemplate(t *testing.T) {
t.Cleanup(cancel)

options := rp.NewRPTestOptions(t)
cli := newCLIWithoutDefaultEnvironment(t, options)

// Create a custom config file without a default environment to test the scenario.

// Get the connection details from the existing workspace
connectionKind := options.Workspace.Connection["kind"]
connectionContext := options.Workspace.Connection["context"]

// Create a temporary config file with workspace that has NO default environment
tempConfigFile, err := os.CreateTemp("", "rad-test-config-*.yaml")
require.NoError(t, err, "Failed to create temp config file")
defer os.Remove(tempConfigFile.Name())

// Build config YAML with workspace but NO environment field
configYAML := fmt.Sprintf(`workspaces:
default: test-workspace
items:
test-workspace:
connection:
kind: %v
context: %v
`, connectionKind, connectionContext)

_, err = tempConfigFile.WriteString(configYAML)
require.NoError(t, err, "Failed to write config file")
err = tempConfigFile.Close()
require.NoError(t, err, "Failed to close config file")

// Use CLI with the custom config that has no default environment
cli := radcli.NewCLI(t, tempConfigFile.Name())

// Generate a unique resource group name to avoid conflicts with parallel tests
uniqueGroupName := fmt.Sprintf("test-deploy-env-group-%s", uuid.New().String())
cwd, err := os.Getwd()
require.NoError(t, err)

// Generate a unique suffix so the resource group and Kubernetes namespace do
// not collide with parallel, repeated, or stale runs against the same cluster.
uniqueSuffix := uuid.New().String()
uniqueGroupName := fmt.Sprintf("test-deploy-env-group-%s", uniqueSuffix)
envName := "test-deploy-env"
envNamespace := fmt.Sprintf("default-test-deploy-env-%s", uniqueSuffix)

// Ensure cleanup even if test fails
t.Cleanup(func() {
deleteKubernetesNamespace(context.Background(), t, options, envNamespace)
})
t.Cleanup(func() {
// Try to delete the test group if it still exists
// Ignore errors as the group might have been successfully deleted
Expand All @@ -84,20 +65,20 @@ func Test_DeployEnvironmentTemplate(t *testing.T) {
err = cli.GroupCreate(ctx, uniqueGroupName)
require.NoError(t, err, "Failed to create resource group")

createKubernetesNamespace(ctx, t, options, envNamespace)

// Get the template file path
cwd, err := os.Getwd()
require.NoError(t, err)
templateFilePath := filepath.Join(cwd, "testdata/corerp-env-deploy-test.bicep")

// Deploy the environment template without specifying --environment flag
t.Logf("Deploying environment template to group: %s without --environment flag", uniqueGroupName)
err = cli.DeployWithGroup(ctx, templateFilePath, "", "", uniqueGroupName)
err = cli.DeployWithGroup(ctx, templateFilePath, "", "", uniqueGroupName, "envNamespace="+envNamespace)
require.NoError(t, err, "Failed to deploy environment template")

// Verify environment was created successfully
t.Logf("Verifying environment was created: %s", envName)
showOpts := radcli.ShowOptions{Group: uniqueGroupName}
output, err := cli.ResourceShow(ctx, "Applications.Core/environments", envName, showOpts)
output, err := cli.ResourceShow(ctx, "Radius.Core/environments", envName, showOpts)
require.NoError(t, err, "Failed to show environment %s", envName)
require.Contains(t, output, envName, "Environment %s should exist", envName)

Expand Down
77 changes: 77 additions & 0 deletions test/functional-portable/cli/noncloud/namespace_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2023 The Radius Authors.

Licensed 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 resource_test

import (
"context"
"fmt"
"os"
"testing"

"github.com/radius-project/radius/pkg/cli/kubernetes"
"github.com/radius-project/radius/test/radcli"
"github.com/radius-project/radius/test/rp"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func newCLIWithoutDefaultEnvironment(t *testing.T, options rp.RPTestOptions) *radcli.CLI {
t.Helper()

tempConfigFile, err := os.CreateTemp(t.TempDir(), "rad-test-config-*.yaml")
require.NoError(t, err, "Failed to create temp config file")

configYAML := fmt.Sprintf(`workspaces:
default: test-workspace
items:
test-workspace:
connection:
kind: %v
context: %v
`, options.Workspace.Connection["kind"], options.Workspace.Connection["context"])

_, err = tempConfigFile.WriteString(configYAML)
require.NoError(t, err, "Failed to write config file")
err = tempConfigFile.Close()
require.NoError(t, err, "Failed to close config file")

return radcli.NewCLI(t, tempConfigFile.Name())
}

func createKubernetesNamespace(ctx context.Context, t *testing.T, options rp.RPTestOptions, namespace string) {
t.Helper()

client, err := rp.DeploymentTargetK8sClient(options)
require.NoError(t, err, "failed to build deployment-target Kubernetes client")
require.NoError(t, kubernetes.EnsureNamespace(ctx, client, namespace), "failed to create namespace %s", namespace)
}

func deleteKubernetesNamespace(ctx context.Context, t *testing.T, options rp.RPTestOptions, namespace string) {
t.Helper()

client, err := rp.DeploymentTargetK8sClient(options)
if err != nil {
t.Logf("Warning: Failed to build deployment-target Kubernetes client: %v", err)
return
}

err = client.CoreV1().Namespaces().Delete(ctx, namespace, metav1.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
t.Logf("Warning: Failed to delete namespace %s: %v", namespace, err)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
extension radius

resource env 'Applications.Core/environments@2023-10-01-preview' = {
@description('Specifies the Kubernetes namespace where the environment deploys recipe resources.')
param envNamespace string = 'default-test-deploy-env'

resource env 'Radius.Core/environments@2025-08-01-preview' = {
name: 'test-deploy-env'
properties: {
Comment thread
lakshmimsft marked this conversation as resolved.
compute: {
kind: 'kubernetes'
resourceId: 'self'
namespace: 'default-test-deploy-env'
providers: {
kubernetes: {
namespace: envNamespace
}
}
}
}
14 changes: 7 additions & 7 deletions test/rp/rptest.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func NewPreviewEnvPreSetup(testName string, workspaceScope string, kubernetesNam
// namespace named after the test (ct.Name) is auto-created by CreateInitialResources, so when
// the preview environment uses a different namespace we must create it here before the CLI
// call, otherwise env creation fails with "Namespace '<ns>' does not exist".
nsClient, err := test.deploymentTargetK8sClient()
nsClient, err := DeploymentTargetK8sClient(test.Options)
require.NoError(t, err, "failed to build deployment-target Kubernetes client")
require.NoError(t, kubernetes.EnsureNamespace(ctx, nsClient, kubernetesNamespace), "failed to ensure preview environment namespace exists")

Expand Down Expand Up @@ -331,7 +331,7 @@ func K8sSecretResource(namespace, name, secretType string, kv ...any) unstructur
// CreateInitialResources creates a namespace and creates initial resources from the InitialResources field of the
// RPTest struct. It returns an error if either of these operations fail.
func (ct RPTest) CreateInitialResources(ctx context.Context) error {
nsClient, err := ct.deploymentTargetK8sClient()
nsClient, err := DeploymentTargetK8sClient(ct.Options)
if err != nil {
return fmt.Errorf("failed to build deployment-target Kubernetes client: %w", err)
}
Comment thread
lakshmimsft marked this conversation as resolved.
Expand All @@ -341,8 +341,8 @@ func (ct RPTest) CreateInitialResources(ctx context.Context) error {
}

for _, r := range ct.InitialResources {
if err := kubernetes.EnsureNamespace(ctx, ct.Options.K8sClient, r.GetNamespace()); err != nil {
return fmt.Errorf("failed to create namespace %s: %w", ct.Name, err)
if err := kubernetes.EnsureNamespace(ctx, nsClient, r.GetNamespace()); err != nil {
return fmt.Errorf("failed to create namespace %s: %w", r.GetNamespace(), err)
}
if err := ct.Options.Client.Create(ctx, &r); err != nil {
return fmt.Errorf("failed to create resource %#v: %w", r, err)
Expand All @@ -352,18 +352,18 @@ func (ct RPTest) CreateInitialResources(ctx context.Context) error {
return nil
}

// deploymentTargetK8sClient returns the Kubernetes client for the cluster that an
// DeploymentTargetK8sClient returns the Kubernetes client for the cluster that an
// application's resources deploy to. In multi-cluster runs the test sets
// RADIUS_TEST_EXTERNAL_KUBECONFIG to the external (workload) cluster's kubeconfig;
// this mirrors the RADIUS_TARGET_KUBECONFIG contract Radius itself honors, so the
// harness provisions the application namespace on the same cluster Radius deploys
// to and the control-plane cluster is not populated with per-application
// namespaces. When the variable is unset (single-cluster runs) the control-plane
// client is returned unchanged.
func (ct RPTest) deploymentTargetK8sClient() (k8sclient.Interface, error) {
func DeploymentTargetK8sClient(options RPTestOptions) (k8sclient.Interface, error) {
kubeconfigPath := os.Getenv(externalKubeconfigEnvVar)
if kubeconfigPath == "" {
return ct.Options.K8sClient, nil
return options.K8sClient, nil
}

config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
Expand Down
Loading