2022-12-08 13:05:19 -03:00

224 lines
6.0 KiB
Go

// Copyright (c) 2021 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.
package integration
import (
"context"
"flag"
"fmt"
"math/rand"
"os"
"testing"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
"sigs.k8s.io/e2e-framework/klient"
"sigs.k8s.io/e2e-framework/pkg/env"
"sigs.k8s.io/e2e-framework/pkg/envconf"
"sigs.k8s.io/e2e-framework/pkg/flags"
)
func SkipWithoutUsername(t *testing.T, username string) {
if username == "" {
t.Skip("Skipping because requires a username")
}
}
func SkipWithoutUserToken(t *testing.T, userToken string) {
if userToken == "" {
t.Skip("Skipping because requires a user token")
}
}
func SkipWithoutEnterpriseLicense(t *testing.T, enterpise bool) {
if !enterpise {
t.Skip("Skipping because requires enterprise license")
}
}
func EnsureUserExists(t *testing.T, username string, api *ComponentAPI) string {
if username == "" {
t.Logf("no username provided, creating temporary one")
rand.Seed(time.Now().UnixNano())
randN := rand.Intn(1000)
newUser := fmt.Sprintf("johndoe%d", randN)
userId, err := CreateUser(newUser, false, api)
if err != nil {
t.Fatalf("cannot create user: %q", err)
}
t.Cleanup(func() {
err := DeleteUser(userId, api)
if err != nil {
t.Fatalf("error deleting user %q", err)
}
})
t.Logf("user '%s' with ID %s created", newUser, userId)
return newUser
}
return username
}
func Setup(ctx context.Context) (string, string, env.Environment, bool, string, bool) {
var (
username string
enterprise bool
gitlab bool
waitGitpodReady time.Duration
namespace string
kubeconfig string
feature string
assess string
parallel bool
labels = make(flags.LabelsMap)
)
flagset := flag.CommandLine
klog.InitFlags(flagset)
flagset.StringVar(&username, "username", "", "username to execute the tests with. Chooses one automatically if left blank.")
flagset.BoolVar(&enterprise, "enterprise", false, "whether to test enterprise features. requires enterprise lisence installed.")
flagset.BoolVar(&gitlab, "gitlab", false, "whether to test gitlab integration.")
flagset.BoolVar(&parallel, "parallel", false, "Run test features in parallel")
flagset.DurationVar(&waitGitpodReady, "wait-gitpod-timeout", 5*time.Minute, `wait time for Gitpod components before starting integration test`)
flagset.StringVar(&namespace, "namespace", "", "Kubernetes cluster namespaces to use")
flagset.StringVar(&kubeconfig, "kubeconfig", "", "The path to the kubeconfig file")
flagset.StringVar(&feature, "feature", "", "Regular expression that targets features to test")
flagset.StringVar(&assess, "assess", "", "Regular expression that targets assertive steps to run")
flagset.Var(&labels, "labels", "Comma-separated key/value pairs to filter tests by labels")
if err := flagset.Parse(os.Args[1:]); err != nil {
klog.Fatalf("cannot parse flags: %v", err)
}
e := envconf.New()
if assess != "" {
e.WithAssessmentRegex(assess)
}
if feature != "" {
e.WithFeatureRegex(feature)
}
if parallel {
e.WithParallelTestEnabled()
}
client, err := klient.NewWithKubeConfigFile(kubeconfig)
if err != nil {
klog.Fatalf("unexpected error: %v", err)
}
e.WithClient(client)
e.WithLabels(labels)
e.WithNamespace(namespace)
// use the namespace from the CurrentContext
if namespace == "" {
ns, err := getNamespace(kubeconfig)
if err != nil {
klog.Fatalf("unexpected error obtaining context namespace: %v", err)
}
e.WithNamespace(ns)
}
testenv, err := env.NewWithContext(ctx, e)
if err != nil {
klog.Fatalf("unexpected error: %v", err)
}
testenv.Setup(
waitOnGitpodRunning(e.Namespace(), waitGitpodReady),
)
return username, e.Namespace(), testenv, enterprise, kubeconfig, gitlab
}
func waitOnGitpodRunning(namespace string, waitTimeout time.Duration) env.Func {
klog.V(2).Info("Checking status of Gitpod components...")
return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) {
components := []string{
"agent-smith",
"blobserve",
"content-service",
"dashboard",
"image-builder-mk3",
"proxy",
"registry-facade",
"server",
"ws-daemon",
"ws-manager",
"ws-manager-bridge",
"ws-proxy",
}
client := cfg.Client()
err := wait.PollImmediate(5*time.Second, waitTimeout, func() (bool, error) {
for _, component := range components {
var pods corev1.PodList
err := client.Resources(namespace).List(context.Background(), &pods, func(opts *metav1.ListOptions) {
opts.LabelSelector = fmt.Sprintf("component=%v", component)
})
if err != nil {
klog.Errorf("unexpected error searching Gitpod components: %v", err)
return false, nil
}
if len(pods.Items) == 0 {
klog.Warningf("no pod ready for component %v", component)
return false, nil
}
for _, p := range pods.Items {
var isReady bool
for _, cond := range p.Status.Conditions {
if cond.Type == corev1.PodReady {
isReady = cond.Status == corev1.ConditionTrue
break
}
}
if !isReady {
klog.Warningf("no pod ready for component %v", component)
return false, nil
}
}
}
klog.V(2).Info("All Gitpod components are running...")
return true, nil
})
if err != nil {
return ctx, nil
}
return ctx, nil
}
}
func getNamespace(path string) (string, error) {
var cfg clientcmd.ClientConfig
switch path {
case "":
loadingrules := clientcmd.NewDefaultClientConfigLoadingRules()
cfg = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingrules,
&clientcmd.ConfigOverrides{})
default:
cfg = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
&clientcmd.ClientConfigLoadingRules{ExplicitPath: path},
&clientcmd.ConfigOverrides{})
}
namespace, _, err := cfg.Namespace()
if err != nil {
return "", err
}
return namespace, nil
}