From 55b66aaff0d3a205a7d46dd809f20b835f2d7098 Mon Sep 17 00:00:00 2001
From: Xie Zheng <xie.zheng@broadcom.com>
Date: Mon, 18 Nov 2024 17:41:06 +0800
Subject: [PATCH] Add e2e test case for IPAddressAllocation

---
 .../ipaddressallocation_external.yaml         |   7 +
 .../ipaddressallocation_private.yaml          |   7 +
 .../ipaddressallocation_privatetgw.yaml       |   7 +
 test/e2e/nsx_ipaddressallocation_test.go      | 132 ++++++++++++++++++
 4 files changed, 153 insertions(+)
 create mode 100644 test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_external.yaml
 create mode 100644 test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_private.yaml
 create mode 100644 test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_privatetgw.yaml
 create mode 100644 test/e2e/nsx_ipaddressallocation_test.go

diff --git a/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_external.yaml b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_external.yaml
new file mode 100644
index 000000000..7c4373a3f
--- /dev/null
+++ b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_external.yaml
@@ -0,0 +1,7 @@
+apiVersion: crd.nsx.vmware.com/v1alpha1
+kind: IPAddressAllocation
+metadata:
+  name: guestcluster-workers-b
+spec:
+  ipAddressBlockVisibility: External
+  allocationSize: 32
\ No newline at end of file
diff --git a/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_private.yaml b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_private.yaml
new file mode 100644
index 000000000..5045b4b91
--- /dev/null
+++ b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_private.yaml
@@ -0,0 +1,7 @@
+apiVersion: crd.nsx.vmware.com/v1alpha1
+kind: IPAddressAllocation
+metadata:
+  name: guestcluster-workers-a
+spec:
+  ipAddressBlockVisibility: Private
+  allocationSize: 32
\ No newline at end of file
diff --git a/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_privatetgw.yaml b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_privatetgw.yaml
new file mode 100644
index 000000000..6ad3f306f
--- /dev/null
+++ b/test/e2e/manifest/testIPAddressAllocation/ipaddressallocation_privatetgw.yaml
@@ -0,0 +1,7 @@
+apiVersion: crd.nsx.vmware.com/v1alpha1
+kind: IPAddressAllocation
+metadata:
+  name: guestcluster-workers-c
+spec:
+  ipAddressBlockVisibility: PrivateTGW
+  allocationSize: 256
\ No newline at end of file
diff --git a/test/e2e/nsx_ipaddressallocation_test.go b/test/e2e/nsx_ipaddressallocation_test.go
new file mode 100644
index 000000000..ae78cddc7
--- /dev/null
+++ b/test/e2e/nsx_ipaddressallocation_test.go
@@ -0,0 +1,132 @@
+package e2e
+
+import (
+	"context"
+	"fmt"
+	"net"
+	"path/filepath"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+	"k8s.io/apimachinery/pkg/api/errors"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/wait"
+
+	"github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1"
+)
+
+const (
+	externalCIDR   = "192.168.0.0/16"
+	privateCIDR    = "172.26.0.0/16"
+	privateTGWCIDR = "10.246.0.0/16"
+	ns             = "test-ipaddress-allocation"
+)
+
+func TestIPAddressAllocation(t *testing.T) {
+	setupTest(t, ns)
+	defer teardownTest(t, ns, defaultTimeout)
+	t.Run("testIPAddressAllocationExternal", func(t *testing.T) {
+		testIPAddressAllocation(t, "./manifest/testIPAddressAllocation/ipaddressallocation_external.yaml", externalCIDR)
+	})
+	t.Run("testIPAddressAllocationPrivate", func(t *testing.T) {
+		testIPAddressAllocation(t, "./manifest/testIPAddressAllocation/ipaddressallocation_private.yaml", privateCIDR)
+	})
+	t.Run("testIPAddressAllocationPrivateTGW", func(t *testing.T) {
+		testIPAddressAllocation(t, "./manifest/testIPAddressAllocation/ipaddressallocation_privatetgw.yaml", privateTGWCIDR)
+	})
+}
+
+func testIPAddressAllocation(t *testing.T, yamlPath string, expectedCIDR string) {
+	deadlineCtx, deadlineCancel := context.WithTimeout(context.Background(), defaultTimeout)
+	defer deadlineCancel()
+
+	var err error
+
+	// Parse YAML to get CR's name
+	ipAllocPath, _ := filepath.Abs(yamlPath)
+	require.NoError(t, applyYAML(ipAllocPath, ns))
+
+	// Assume the name is the same as defined in the respective YAML
+	ipAllocName := getNameFromYAML(ipAllocPath)
+	assureIPAddressAllocationReady(t, ns, ipAllocName)
+
+	// Check AllocationIPs
+	assertAllocationCIDR(t, ns, ipAllocName, expectedCIDR)
+
+	// Delete IPAddressAllocation
+	_ = deleteYAML(ipAllocPath, ns)
+
+	err = wait.PollUntilContextTimeout(deadlineCtx, 1*time.Second, defaultTimeout, false, func(ctx context.Context) (done bool, err error) {
+		resp, err := testData.crdClientset.CrdV1alpha1().IPAddressAllocations(ns).Get(ctx, ipAllocName, v1.GetOptions{})
+		log.V(2).Info("Check resource", "resp", resp)
+		if err != nil {
+			if errors.IsNotFound(err) {
+				return true, nil
+			}
+			return false, fmt.Errorf("error when waiting for IPAddressAllocation %s", ipAllocName)
+		}
+		return false, nil
+	})
+	require.NoError(t, err)
+}
+
+func assureIPAddressAllocationReady(t *testing.T, ns, ipAllocName string) {
+	deadlineCtx, deadlineCancel := context.WithTimeout(context.Background(), defaultTimeout)
+	defer deadlineCancel()
+	err := wait.PollUntilContextTimeout(deadlineCtx, 1*time.Second, defaultTimeout, false, func(ctx context.Context) (done bool, err error) {
+		resp, err := testData.crdClientset.CrdV1alpha1().IPAddressAllocations(ns).Get(context.Background(), ipAllocName, v1.GetOptions{})
+		log.V(2).Info("Get IPAddressAllocations", "Namespace", ns, "Name", ipAllocName)
+		if err != nil {
+			return false, fmt.Errorf("error when waiting for %s", ipAllocName)
+		}
+		for _, con := range resp.Status.Conditions {
+			if con.Type == v1alpha1.Ready && resp.Status.AllocationIPs != "" {
+				return true, nil
+			}
+		}
+		return false, nil
+	})
+	require.NoError(t, err)
+}
+
+func assertAllocationCIDR(t *testing.T, ns, ipAllocName, expectedCIDR string) {
+	_, expectedNet, err := net.ParseCIDR(expectedCIDR)
+	require.NoError(t, err)
+
+	deadlineCtx, deadlineCancel := context.WithTimeout(context.Background(), defaultTimeout)
+	defer deadlineCancel()
+	err = wait.PollUntilContextTimeout(deadlineCtx, 1*time.Second, defaultTimeout, false, func(ctx context.Context) (bool, error) {
+		resp, err := testData.crdClientset.CrdV1alpha1().IPAddressAllocations(ns).Get(context.Background(), ipAllocName, v1.GetOptions{})
+		if err != nil {
+			return false, err
+		}
+		if resp.Status.AllocationIPs != "" {
+			allocCIDR := resp.Status.AllocationIPs
+			_, allocNet, err := net.ParseCIDR(allocCIDR)
+			if err != nil {
+				return false, err
+			}
+			if expectedNet.Contains(allocNet.IP) && allocNet.Contains(expectedNet.IP) {
+				return true, nil
+			}
+			return true, nil
+		}
+		return false, nil
+	})
+	require.NoError(t, err, "Failed to verify AllocationIPs CIDR for IPAddressAllocation %s", ipAllocName)
+}
+
+func getNameFromYAML(yamlPath string) string {
+	// Manually extract the CR's name from the filename, adjust logic if necessary
+	switch filepath.Base(yamlPath) {
+	case "ipaddressallocation_external.yaml":
+		return "guestcluster-workers-b"
+	case "ipaddressallocation_private.yaml":
+		return "guestcluster-workers-a"
+	case "ipaddressallocation_privatetgw.yaml":
+		return "guestcluster-workers-c"
+	default:
+		panic("Unknown YAML file")
+	}
+}