Skip to content

Commit

Permalink
create test case for hello-world sample
Browse files Browse the repository at this point in the history
update ensureNamespace function

update ensureNamespace function
  • Loading branch information
linyguo committed Jul 31, 2024
1 parent 1b779a4 commit 1aa1992
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ jobs:
- name: Run integration tests 05
run: |
cd test/integration/scenarios/05.catalog/ && mage test
- name: Run integration tests 07
run: |
cd test/integration/scenarios/07.helloWorld/ && mage test
- name: Collect and upload symphony logs
uses: actions/upload-artifact@v2
Expand Down
32 changes: 32 additions & 0 deletions test/integration/lib/testhelpers/kubeutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
package testhelpers

import (
"context"
"flag"
"path/filepath"
"sync"

corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
Expand Down Expand Up @@ -65,3 +69,31 @@ func RestConfig() (*rest.Config, error) {

return configInst, nil
}

// Ensures that the namespace exists. If it does not exist, it creates it.
func EnsureNamespace(namespace string) error {
kubeClient, err := KubeClient()
if err != nil {
return err
}

_, err = kubeClient.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{})
if err == nil {
return nil
}

if kerrors.IsNotFound(err) {
_, err = kubeClient.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}, metav1.CreateOptions{})
if err != nil {
return err
}
} else {
return err
}

return nil
}
107 changes: 107 additions & 0 deletions test/integration/scenarios/07.helloWorld/magefile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//go:build mage

/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
* SPDX-License-Identifier: MIT
*/

package main

import (
"fmt"
"os"
"path/filepath"

"github.com/eclipse-symphony/symphony/test/integration/lib/testhelpers"
"github.com/princjef/mageutil/shellcmd"
)

// Test config
const (
NAMESPACE = "sample-k8s-scope"
TEST_NAME = "Symphony Hello World sample test scenario"
TEST_TIMEOUT = "10m"
)

var (
// Manifests to deploy
testManifests = []string{
"../../../../docs/samples/k8s/hello-world/solution-container.yaml",
"../../../../docs/samples/k8s/hello-world//solution.yaml",
"../../../../docs/samples/k8s/hello-world//target.yaml",
"../../../../docs/samples/k8s/hello-world//instance.yaml",
}

// Tests to run
testVerify = []string{
"./verify/...",
}
)

// Entry point for running the tests
func Test() error {
fmt.Println("Running ", TEST_NAME)

defer testhelpers.Cleanup(TEST_NAME)

err := testhelpers.SetupCluster()
if err != nil {
return err
}

// Deploy solution, target and instance
err = DeployManifests()
if err != nil {
return err
}

err = Verify()
if err != nil {
return err
}

return nil
}

// Run tests
func Verify() error {
err := shellcmd.Command("go clean -testcache").Run()
if err != nil {
return err
}
os.Setenv("SYMPHONY_FLAVOR", "oss")
for _, verify := range testVerify {
err := shellcmd.Command(fmt.Sprintf("go test -timeout %s %s", TEST_TIMEOUT, verify)).Run()
if err != nil {
return err
}
}

return nil
}

// Deploy solution, target and instance
func DeployManifests() error {
// Get kube client
err := testhelpers.EnsureNamespace(NAMESPACE)
if err != nil {
return err
}

currentPath, err := os.Getwd()
if err != nil {
return err
}

// Deploy the manifests
for _, manifest := range testManifests {
manifestPath := filepath.Join(currentPath, manifest)
err = shellcmd.Command(fmt.Sprintf("kubectl apply -f %s -n %s", manifestPath, NAMESPACE)).Run()
if err != nil {
return err
}
}

return nil
}
138 changes: 138 additions & 0 deletions test/integration/scenarios/07.helloWorld/verify/manifest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
* SPDX-License-Identifier: MIT
*/

package verify

import (
"context"
"fmt"
"strings"
"testing"
"time"

"github.com/eclipse-symphony/symphony/test/integration/lib/testhelpers"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)

// Test config
var (
NAMESPACE = "sample-k8s-scope"
)

// Verify target has correct status
func Test_VerifyTargetStatus(t *testing.T) {
// Verify target
cfg, err := testhelpers.RestConfig()
require.NoError(t, err)

dyn, err := dynamic.NewForConfig(cfg)
require.NoError(t, err)

for {
resources, err := dyn.Resource(schema.GroupVersionResource{
Group: "fabric.symphony",
Version: "v1",
Resource: "targets",
}).Namespace(NAMESPACE).List(context.Background(), metav1.ListOptions{})
require.NoError(t, err)

require.Len(t, resources.Items, 1, "there should be only one target")

status := getStatus(resources.Items[0])
fmt.Printf("Current target status: %s\n", status)
require.NotEqual(t, "Failed", status, "target should not be in failed state")
if status == "Succeeded" {
break
}

sleepDuration, _ := time.ParseDuration("30s")
time.Sleep(sleepDuration)
}
}

// Verify instance has correct status
func Test_VerifyInstanceStatus(t *testing.T) {
// Verify instance
cfg, err := testhelpers.RestConfig()
require.NoError(t, err)

dyn, err := dynamic.NewForConfig(cfg)
require.NoError(t, err)

for {
resources, err := dyn.Resource(schema.GroupVersionResource{
Group: "solution.symphony",
Version: "v1",
Resource: "instances",
}).Namespace(NAMESPACE).List(context.Background(), metav1.ListOptions{})
require.NoError(t, err)

require.Len(t, resources.Items, 1, "there should be only one instance")

status := getStatus(resources.Items[0])
fmt.Printf("Current instance status: %s\n", status)
require.NotEqual(t, "Failed", status, "instance should not be in failed state")
if status == "Succeeded" {
break
}

sleepDuration, _ := time.ParseDuration("30s")
time.Sleep(sleepDuration)
}
}

func TestBasic_VerifyPodsExist(t *testing.T) {
// Get kube client
kubeClient, err := testhelpers.KubeClient()
require.NoError(t, err)

i := 0
for {
i++

// List all pods in the namespace
pods, err := kubeClient.CoreV1().Pods(NAMESPACE).List(context.Background(), metav1.ListOptions{})
require.NoError(t, err)

found := false
for _, pod := range pods.Items {
if strings.Contains(pod.Name, "sample-prometheus-instance") && pod.Status.Phase == "Running" {
found = true
break
}
}

if found {
break
} else {
time.Sleep(time.Second * 5)

if i%12 == 0 {
fmt.Printf("Waiting for pods: sample-prometheus-instance\n")
}
}
}
}

// Helper for finding the status
func getStatus(resource unstructured.Unstructured) string {
status, ok := resource.Object["status"].(map[string]interface{})
if ok {
props, ok := status["provisioningStatus"].(map[string]interface{})
if ok {
statusString, ok := props["status"].(string)
if ok {
return statusString
}
}
}

return ""
}

0 comments on commit 1aa1992

Please sign in to comment.