Skip to content

Commit

Permalink
Merge pull request #90 from flacatus/e2e_tests
Browse files Browse the repository at this point in the history
Add basic tests for cloud shell
  • Loading branch information
flacatus authored Jun 5, 2020
2 parents b7f53c9 + 5a56e1b commit 19ebfea
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 0 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ require (
)

require (
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/operator-framework/operator-sdk v0.17.0
github.com/spf13/pflag v1.0.5
k8s.io/api v0.17.4
Expand Down
98 changes: 98 additions & 0 deletions test/e2e/cmd/workspaces_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package cmd

import (
"fmt"
"path/filepath"
"testing"

"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/config"
"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/deploy"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/client"
_ "github.com/che-incubator/che-workspace-operator/test/e2e/pkg/tests"
"github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/gomega"
)

//Create Constant file
const (
testResultsDirectory = "/tmp/artifacts"
jUnitOutputFilename = "junit-workspaces-operator.xml"
)

//SynchronizedBeforeSuite blocks is executed before run all test suites
var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
//!TODO: Try to create a specific function to call all <ginkgo suite> configuration.
fmt.Println("Starting to setup objects before run ginkgo suite")
config.Namespace = "che-workspace-controller"

k8sClient, err := client.NewK8sClient()
if err != nil {
fmt.Println("Failed to create workspace client")
panic(err)
}

controller := deploy.NewDeployment(k8sClient)

err = controller.CreateNamespace()
if err != nil {
panic(err)
}

//TODO: Have better improvement of errors.
if err := controller.CreateAllOperatorRoles(); err != nil {
_ = fmt.Errorf("Failed to create roles in clusters %s", err)
}

if err := controller.CreateOperatorClusterRole(); err != nil {
_ = fmt.Errorf("Failed to create cluster roles in clusters %s", err)
}

if err := controller.CustomResourceDefinitions(); err != nil {
_ = fmt.Errorf("Failed to add custom resources definitions to cluster %s", err)
}

if err := controller.DeployWorkspacesController(); err != nil {
_ = fmt.Errorf("Failed to deploy workspace controller %s", err)
}

return nil
}, func(data []byte) {})

var _ = ginkgo.SynchronizedAfterSuite(func() {
k8sClient, err := client.NewK8sClient()

if err != nil {
_ = fmt.Errorf("Failed to uninstall workspace controller %s", err)
}

if err = k8sClient.Kube().CoreV1().Namespaces().Delete(config.Namespace, &metav1.DeleteOptions{}); err != nil {
_ = fmt.Errorf("Failed to uninstall workspace controller %s", err)
}
}, func() {})

func TestWorkspaceController(t *testing.T) {
gomega.RegisterFailHandler(ginkgo.Fail)

fmt.Println("Creating ginkgo reporter for Test Harness: Junit and Debug Detail reporter")
var r []ginkgo.Reporter
r = append(r, reporters.NewJUnitReporter(filepath.Join(testResultsDirectory, jUnitOutputFilename)))

fmt.Println("Running Workspace Controller e2e tests...")
ginkgo.RunSpecsWithDefaultAndCustomReporters(t, "Workspaces Controller Operator Tests", r)
}
42 changes: 42 additions & 0 deletions test/e2e/pkg/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package client

import (
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)

type K8sClient struct {
kubeClient *kubernetes.Clientset
}

// NewK8sClient creates kubernetes client wrapper with helper functions and direct access to k8s go client
func NewK8sClient() (*K8sClient, error) {
cfg, err := config.GetConfig()
if err != nil {
return nil, err
}
client, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, err
}

h := &K8sClient{kubeClient: client}
return h, nil
}

// Kube returns the clientset for Kubernetes upstream.
func (c *K8sClient) Kube() kubernetes.Interface {
return c.kubeClient
}
30 changes: 30 additions & 0 deletions test/e2e/pkg/client/oc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package client

import (
"fmt"
"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/config"
"os/exec"
"strings"
)

func (w *K8sClient) OcApply(filePath string) (err error) {
cmd := exec.Command("oc", "apply", "--namespace", config.Namespace, "-f", filePath)
output, err := cmd.CombinedOutput()
fmt.Println(string(output))
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
fmt.Println(err)
}
return err
}
100 changes: 100 additions & 0 deletions test/e2e/pkg/client/pod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package client

import (
"errors"
"fmt"
"time"

"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/config"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
)

func (w *K8sClient) WaitForPodRunningByLabel(label string) (deployed bool, err error) {
timeout := time.After(15 * time.Minute)
tick := time.Tick(1 * time.Second)

for {
select {
case <-timeout:
return false, errors.New("timed out")
case <-tick:
err := w.WaitForRunningPodBySelector(config.Namespace, label, 3*time.Minute)
if err == nil {
return true, nil
}
}
}
}

// Wait up to timeout seconds for all pods in 'namespace' with given 'selector' to enter running state.
// Returns an error if no pods are found or not all discovered pods enter running state.
func (w *K8sClient) WaitForRunningPodBySelector(namespace, selector string, timeout time.Duration) error {
podList, err := w.ListPods(namespace, selector)
if err != nil {
return err
}
if len(podList.Items) == 0 {
fmt.Println("Pod not created yet with selector " + selector + " in namespace " + namespace)

return fmt.Errorf("Pod not created yet in %s with label %s", namespace, selector)
}

for _, pod := range podList.Items {
fmt.Println("Pod " + pod.Name + " created in namespace " + namespace + "...Checking startup data.")
if err := w.waitForPodRunning(namespace, pod.Name, timeout); err != nil {
return err
}
}

return nil
}

// Returns the list of currently scheduled or running pods in `namespace` with the given selector
func (w *K8sClient) ListPods(namespace, selector string) (*v1.PodList, error) {
listOptions := metav1.ListOptions{LabelSelector: selector}
podList, err := w.Kube().CoreV1().Pods(namespace).List(listOptions)

if err != nil {
return nil, err
}
return podList, nil
}

// Poll up to timeout seconds for pod to enter running state.
// Returns an error if the pod never enters the running state.
func (w *K8sClient) waitForPodRunning(namespace, podName string, timeout time.Duration) error {
return wait.PollImmediate(time.Second, timeout, w.isPodRunning(podName, namespace))
}

// return a condition function that indicates whether the given pod is
// currently running
func (w *K8sClient) isPodRunning(podName, namespace string) wait.ConditionFunc {
return func() (bool, error) {
pod, _ := w.Kube().CoreV1().Pods(namespace).Get(podName, metav1.GetOptions{})
age := time.Since(pod.GetCreationTimestamp().Time).Seconds()

switch pod.Status.Phase {
case v1.PodRunning:
fmt.Println("Pod started after", age, "seconds")
return true, nil
case v1.PodFailed, v1.PodSucceeded:
return false, nil
}
return false, nil
}
}
15 changes: 15 additions & 0 deletions test/e2e/pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package config

var Namespace string
81 changes: 81 additions & 0 deletions test/e2e/pkg/deploy/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// Copyright (c) 2019-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package deploy

import (
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"os/exec"
"strings"

"github.com/che-incubator/che-workspace-operator/test/e2e/pkg/config"
)

func (w *Deployment) CreateNamespace() error {
_, err := w.kubeClient.Kube().CoreV1().Namespaces().Create(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: config.Namespace,
},
})
return err
}

func (w *Deployment) DeployWorkspacesController() error {
label := "app=che-workspace-controller"
cmd := exec.Command("oc", "apply", "--namespace", config.Namespace, "-f", "deploy/os")
output, err := cmd.CombinedOutput()
fmt.Println(string(output))
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
fmt.Println(err)
return err
}

deploy, err := w.kubeClient.WaitForPodRunningByLabel(label)
if !deploy || err != nil {
fmt.Println("Che Workspaces Controller not deployed")
return err
}
return nil
}

func (w *Deployment) CreateAllOperatorRoles() error {
cmd := exec.Command("oc", "apply", "--namespace", config.Namespace, "-f", "deploy")
output, err := cmd.CombinedOutput()
fmt.Println(string(output))
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
fmt.Println(err)
return err
}
return nil
}

func (w *Deployment) CustomResourceDefinitions() error {
cmd := exec.Command("oc", "apply", "-f", "deploy/crds")
output, err := cmd.CombinedOutput()
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
fmt.Println(err)
return err
}
return nil
}

func (w *Deployment) CreateOperatorClusterRole() error {
cmd := exec.Command("oc", "apply", "--namespace", config.Namespace, "-f", "deploy/role.yaml")
output, err := cmd.CombinedOutput()
if err != nil && !strings.Contains(string(output), "AlreadyExists") {
fmt.Println(err)
return err
}
return nil
}
Loading

0 comments on commit 19ebfea

Please sign in to comment.