diff --git a/Makefile b/Makefile index 75d7818b4..874525da6 100644 --- a/Makefile +++ b/Makefile @@ -194,11 +194,15 @@ check-podman: .PHONY: test test: podman-check manifests generate fmt vet envtest ginkgo - FAST_TEST=false KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) --repeat 4 $(if $(TEST_FOCUS),-focus $(TEST_FOCUS),) ./... -coverprofile cover.out + FAST_TEST=false KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) --repeat 4 $(if $(TEST_FOCUS),-focus $(TEST_FOCUS),) ./internal/... -coverprofile cover.out -.PHONY: test +.PHONY: fast-test fast-test: envtest ginkgo - FAST_TEST=true KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) $(if $(TEST_FOCUS),-focus $(TEST_FOCUS),) ./... -coverprofile cover.out + FAST_TEST=true KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) $(if $(TEST_FOCUS),-focus $(TEST_FOCUS),) ./internal/... -coverprofile cover.out +##@ Build +.PHONY: aaaa +aaaa: envtest ginkgo + FAST_TEST=true KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) $(if $(TEST_FOCUS),-focus $(TEST_FOCUS),) ./e2e-test/... -coverprofile cover.out ##@ Build .PHONY: build diff --git a/dpu-cni/pkgs/cniserver/cniserver_test.go b/dpu-cni/pkgs/cniserver/cniserver_test.go index eba30d60f..3734684ab 100644 --- a/dpu-cni/pkgs/cniserver/cniserver_test.go +++ b/dpu-cni/pkgs/cniserver/cniserver_test.go @@ -44,11 +44,11 @@ var _ = g.Describe("Cniserver", func() { listener net.Listener addHandlerCalled bool delHandlerCalled bool - testCluster testutils.TestCluster + testCluster testutils.KindCluster ) g.BeforeEach(func() { - testCluster = testutils.TestCluster{Name: "dpu-operator-test-cluster"} + testCluster = testutils.KindCluster{Name: "dpu-operator-test-cluster"} testCluster.EnsureExists() }) diff --git a/e2e-test/e2e_test.go b/e2e-test/e2e_test.go new file mode 100644 index 000000000..b3db8ed28 --- /dev/null +++ b/e2e-test/e2e_test.go @@ -0,0 +1,138 @@ +package daemon + +import ( + "context" + "testing" + "time" + + g "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + //+kubebuilder:scaffold:imports + configv1 "github.com/openshift/dpu-operator/api/v1" + "github.com/openshift/dpu-operator/internal/testutils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var ( + cfg *rest.Config + testEnv *envtest.Environment + timeout = 10 * time.Second + interval = 1 * time.Second +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(g.Fail) + + g.RunSpecs(t, "e2e tests") +} + +var _ = g.BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(g.GinkgoWriter), zap.UseDevMode(true))) +}) + +var _ = g.AfterSuite(func() { + // Nothing needed +}) + +func getPod(c client.Client, name, namespace string) *corev1.Pod { + podList := &corev1.PodList{} + err := c.List(context.TODO(), podList, client.InNamespace(namespace)) + Expect(err).NotTo(HaveOccurred()) + for _, pod := range podList.Items { + if pod.Name == name { + return &pod + } + } + return nil +} + +var _ = g.Describe("Dpu side", g.Ordered, func() { + var ( + err error + dpuSideClient client.Client + ) + + g.BeforeEach(func() { + cluster := testutils.CdaCluster{ + Name: "", + HostConfigPath: "hack/cluster-configs/config-dpu-host.yaml", + DpuConfigPath: "hack/cluster-configs/config-dpu.yaml", + } + _, dpuConfig, _ := cluster.EnsureExists() + Expect(err).NotTo(HaveOccurred()) + + scheme := runtime.NewScheme() + utilruntime.Must(configv1.AddToScheme(scheme)) + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + dpuSideClient, err = client.New(dpuConfig, client.Options{Scheme: scheme}) + Expect(err).NotTo(HaveOccurred()) + }) + + g.AfterEach(func() { + }) + + _ = testutils.CdaCluster{Name: "ocpcluster"} + + g.It("Should create a pod when creating an SFC and there is no pod", func() { + nfName := "example-nf" + nfImage := "example-nf-image-url" + ns := "openshift-dpu-operator" + + Eventually(func() bool { + return getPod(dpuSideClient, nfName, ns) != nil + }, timeout, interval).Should(BeFalse()) + + sfc := &configv1.ServiceFunctionChain{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sfc-test", + Namespace: ns, + }, + Spec: configv1.ServiceFunctionChainSpec{ + NetworkFunctions: []configv1.NetworkFunction{ + { + Name: nfName, + Image: nfImage, + }, + }, + }, + } + err := dpuSideClient.Create(context.TODO(), sfc) + Expect(err).NotTo(HaveOccurred()) + + podList := &corev1.PodList{} + err = dpuSideClient.List(context.TODO(), podList, client.InNamespace(ns)) + Expect(err).NotTo(HaveOccurred()) + + Eventually(func() bool { + pod := getPod(dpuSideClient, nfName, ns) + if pod != nil { + println("Pod got") + return pod.Spec.Containers[0].Image == nfImage + } + println("pod not there") + return false + }, timeout, interval).Should(BeTrue()) + + err = dpuSideClient.Delete(context.TODO(), sfc) + Expect(err).NotTo(HaveOccurred()) + + Eventually(func() bool { + return getPod(dpuSideClient, nfName, ns) != nil + }, timeout, interval).Should(BeFalse()) + }) +}) diff --git a/internal/controller/dpuoperatorconfig_controller_test.go b/internal/controller/dpuoperatorconfig_controller_test.go index dbb24972d..3abf5f881 100755 --- a/internal/controller/dpuoperatorconfig_controller_test.go +++ b/internal/controller/dpuoperatorconfig_controller_test.go @@ -181,14 +181,14 @@ var _ = Describe("Main Controller", Ordered, func() { var ctx context.Context var wg sync.WaitGroup var mgr ctrl.Manager - var testCluster testutils.TestCluster + var testCluster testutils.KindCluster BeforeAll(func() { opts := zap.Options{ Development: true, } ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - testCluster = testutils.TestCluster{Name: testClusterName} + testCluster = testutils.KindCluster{Name: testClusterName} client := testCluster.EnsureExists() ctx, cancel = context.WithCancel(context.Background()) wg = sync.WaitGroup{} diff --git a/internal/daemon/dpudaemon_test.go b/internal/daemon/dpudaemon_test.go index 0a30682a0..f575483f3 100644 --- a/internal/daemon/dpudaemon_test.go +++ b/internal/daemon/dpudaemon_test.go @@ -48,11 +48,11 @@ var _ = g.Describe("DPU Daemon", Ordered, func() { var ( dpuDaemon *DpuDaemon config *rest.Config - testCluster testutils.TestCluster + testCluster testutils.KindCluster client client.Client ) g.BeforeEach(func() { - testCluster = testutils.TestCluster{Name: "dpu-operator-test-cluster"} + testCluster = testutils.KindCluster{Name: "dpu-operator-test-cluster"} config = testCluster.EnsureExists() pathManager := *utils.NewPathManager(testCluster.TempDirPath()) diff --git a/internal/daemon/hostdaemon_test.go b/internal/daemon/hostdaemon_test.go index a77bad258..d192c7bf3 100644 --- a/internal/daemon/hostdaemon_test.go +++ b/internal/daemon/hostdaemon_test.go @@ -181,11 +181,11 @@ var _ = g.Describe("Host Daemon", func() { err error fakeDpuDaemon *DummyDpuDaemon hostDaemon *HostDaemon - testCluster *testutils.TestCluster + testCluster *testutils.KindCluster pathManager *utils.PathManager ) g.BeforeEach(func() { - testCluster = &testutils.TestCluster{Name: "dpu-operator-test-cluster"} + testCluster = &testutils.KindCluster{Name: "dpu-operator-test-cluster"} testCluster.EnsureExists() pathManager = utils.NewPathManager(testCluster.TempDirPath()) Expect(err).NotTo(HaveOccurred()) diff --git a/internal/testutils/cdacluster.go b/internal/testutils/cdacluster.go new file mode 100644 index 000000000..3e76fdf0b --- /dev/null +++ b/internal/testutils/cdacluster.go @@ -0,0 +1,62 @@ +package testutils + +import ( + "os" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +type CdaCluster struct { + Name string + HostConfigPath string + DpuConfigPath string +} + +func (t *CdaCluster) EnsureExists() (*rest.Config, *rest.Config, error) { + hostConfig, err := t.createClient("/root/kubeconfig.ocpcluster") + if err != nil { + return nil, nil, err + } + dpuConfig, err := t.createClient("/root/kubeconfig.microshift") + if err != nil { + return nil, nil, err + } + return hostConfig, dpuConfig, nil +} + +func (t *CdaCluster) createClient(kubeconfigPath string) (*rest.Config, error) { + kubeconfig, err := readToByte(kubeconfigPath) + if err != nil { + return nil, err + } + config, err := clientcmd.NewClientConfigFromBytes(kubeconfig) + if err != nil { + return nil, err + } + restCfg, err := config.ClientConfig() + if err != nil { + return nil, err + } + return restCfg, nil +} + +func readToByte(path string) ([]byte, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + stats, err := f.Stat() + if err != nil { + return nil, err + } + + cfg := make([]byte, stats.Size()) + _, err = f.Read(cfg) + if err != nil { + return nil, err + } + return cfg, nil +} diff --git a/internal/testutils/test_cluster.go b/internal/testutils/kindcluster.go similarity index 91% rename from internal/testutils/test_cluster.go rename to internal/testutils/kindcluster.go index 0955026cb..1e775c6b2 100644 --- a/internal/testutils/test_cluster.go +++ b/internal/testutils/kindcluster.go @@ -63,15 +63,15 @@ func bootstrapTestEnv(restConfig *rest.Config) { Expect(cfg).NotTo(BeNil()) } -type TestCluster struct { +type KindCluster struct { Name string } -func (t *TestCluster) TempDirPath() string { +func (t *KindCluster) TempDirPath() string { return filepath.Join("/tmp", t.Name) } -func (t *TestCluster) ensureTempDir() error { +func (t *KindCluster) ensureTempDir() error { dirPath := t.TempDirPath() _, err := os.Stat(dirPath) if err == nil { @@ -86,7 +86,7 @@ func (t *TestCluster) ensureTempDir() error { return err } -func (t *TestCluster) ensureTempDirDeleted() error { +func (t *KindCluster) ensureTempDirDeleted() error { dirPath := t.TempDirPath() err := os.RemoveAll(dirPath) if err != nil { @@ -95,19 +95,19 @@ func (t *TestCluster) ensureTempDirDeleted() error { return nil } -func (t *TestCluster) EnsureExists() *rest.Config { - client := t.prepareTestCluster() +func (t *KindCluster) EnsureExists() *rest.Config { + client := t.prepareKindCluster() bootstrapTestEnv(client) return client } -func (t *TestCluster) EnsureDeleted() { - deleteKindTestCluster(t.Name) +func (t *KindCluster) EnsureDeleted() { + deleteKindCluster(t.Name) err := t.ensureTempDirDeleted() Expect(err).NotTo(HaveOccurred()) } -func deleteKindTestCluster(name string) { +func deleteKindCluster(name string) { provider := cluster.NewProvider() provider.Delete(name, "") } @@ -148,7 +148,7 @@ func clusterExists(p *cluster.Provider, name string) bool { return false } -func (t *TestCluster) prepareTestCluster() *rest.Config { +func (t *KindCluster) prepareKindCluster() *rest.Config { var cfg []byte var err error diff --git a/internal/testutils/testcluster.go b/internal/testutils/testcluster.go new file mode 100644 index 000000000..72df77a91 --- /dev/null +++ b/internal/testutils/testcluster.go @@ -0,0 +1,10 @@ +package testutils + +import ( + "k8s.io/client-go/rest" +) + +type Cluster interface { + EnsureExists() *rest.Config + EnsureDeleted() +}