mirror of https://github.com/knative/pkg.git
Add some more common test componets in pkg/test (#321)
This commit is contained in:
parent
374ae9eb1f
commit
46bd1f13c2
|
@ -19,8 +19,12 @@ limitations under the License.
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/knative/pkg/test/logging"
|
"github.com/knative/pkg/test/logging"
|
||||||
"github.com/knative/pkg/test/spoof"
|
"github.com/knative/pkg/test/spoof"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
k8styped "k8s.io/client-go/kubernetes/typed/core/v1"
|
k8styped "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
|
@ -67,7 +71,7 @@ func BuildClientConfig(kubeConfigPath string, clusterName string) (*rest.Config,
|
||||||
|
|
||||||
// UpdateConfigMap updates the config map for specified @name with values
|
// UpdateConfigMap updates the config map for specified @name with values
|
||||||
func (client *KubeClient) UpdateConfigMap(name string, configName string, values map[string]string) error {
|
func (client *KubeClient) UpdateConfigMap(name string, configName string, values map[string]string) error {
|
||||||
configMap, err := client.getConfigMap(name).Get(configName, metav1.GetOptions{})
|
configMap, err := client.GetConfigMap(name).Get(configName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -76,11 +80,35 @@ func (client *KubeClient) UpdateConfigMap(name string, configName string, values
|
||||||
configMap.Data[key] = value
|
configMap.Data[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.getConfigMap(name).Update(configMap)
|
_, err = client.GetConfigMap(name).Update(configMap)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getConfigMap gets the knative serving config map.
|
// GetConfigMap gets the knative serving config map.
|
||||||
func (client *KubeClient) getConfigMap(name string) k8styped.ConfigMapInterface {
|
func (client *KubeClient) GetConfigMap(name string) k8styped.ConfigMapInterface {
|
||||||
return client.Kube.CoreV1().ConfigMaps(name)
|
return client.Kube.CoreV1().ConfigMaps(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreatePod will create a Pod
|
||||||
|
func (client *KubeClient) CreatePod(pod *corev1.Pod) (*corev1.Pod, error) {
|
||||||
|
pods := client.Kube.CoreV1().Pods(pod.GetNamespace())
|
||||||
|
return pods.Create(pod)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodLogs returns Pod logs for given Pod and Container
|
||||||
|
func (client *KubeClient) PodLogs(podName, containerName string) ([]byte, error) {
|
||||||
|
pods := client.Kube.CoreV1().Pods(Flags.Namespace)
|
||||||
|
podList, err := pods.List(metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, pod := range podList.Items {
|
||||||
|
if strings.Contains(pod.Name, podName) {
|
||||||
|
result := pods.GetLogs(pod.Name, &corev1.PodLogOptions{
|
||||||
|
Container: containerName,
|
||||||
|
}).Do()
|
||||||
|
return result.Raw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Could not find logs for %s/%s", podName, containerName)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Knative Authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This file contains functions that construct boilerplate CRD definitions.
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nginxPort = 80
|
||||||
|
nginxName = "nginx"
|
||||||
|
nginxImage = "nginx:1.7.9"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceAccount returns ServiceAccount object in given namespace
|
||||||
|
func ServiceAccount(name string, namespace string) *corev1.ServiceAccount {
|
||||||
|
return &corev1.ServiceAccount{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClusterRoleBinding returns ClusterRoleBinding for given subject and role
|
||||||
|
func ClusterRoleBinding(name string, namespace string, serviceAccount string, role string) *rbacv1.ClusterRoleBinding {
|
||||||
|
return &rbacv1.ClusterRoleBinding{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Subjects: []rbacv1.Subject{
|
||||||
|
{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
Name: serviceAccount,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RoleRef: rbacv1.RoleRef{
|
||||||
|
Kind: "ClusterRole",
|
||||||
|
Name: role,
|
||||||
|
APIGroup: "rbac.authorization.k8s.io",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoreV1ObjectReference returns a corev1.ObjectReference for the given name, kind and apiversion
|
||||||
|
func CoreV1ObjectReference(kind, apiversion, name string) *corev1.ObjectReference {
|
||||||
|
return &corev1.ObjectReference{
|
||||||
|
Kind: kind,
|
||||||
|
APIVersion: apiversion,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NginxPod returns nginx pod defined in given namespace
|
||||||
|
func NginxPod(namespace string) *corev1.Pod {
|
||||||
|
return &corev1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: nginxName,
|
||||||
|
Namespace: namespace,
|
||||||
|
Annotations: map[string]string{"sidecar.istio.io/inject": "true"},
|
||||||
|
},
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: nginxName,
|
||||||
|
Image: nginxImage,
|
||||||
|
Ports: []corev1.ContainerPort{
|
||||||
|
{
|
||||||
|
ContainerPort: nginxPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
@ -37,6 +39,8 @@ type EnvironmentFlags struct {
|
||||||
IngressEndpoint string // Host to use for ingress endpoint
|
IngressEndpoint string // Host to use for ingress endpoint
|
||||||
LogVerbose bool // Enable verbose logging
|
LogVerbose bool // Enable verbose logging
|
||||||
EmitMetrics bool // Emit metrics
|
EmitMetrics bool // Emit metrics
|
||||||
|
DockerRepo string // Docker repo (defaults to $KO_DOCKER_REPO)
|
||||||
|
Tag string // Tag for test images
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeFlags() *EnvironmentFlags {
|
func initializeFlags() *EnvironmentFlags {
|
||||||
|
@ -63,5 +67,16 @@ func initializeFlags() *EnvironmentFlags {
|
||||||
flag.BoolVar(&f.EmitMetrics, "emitmetrics", false,
|
flag.BoolVar(&f.EmitMetrics, "emitmetrics", false,
|
||||||
"Set this flag to true if you would like tests to emit metrics, e.g. latency of resources being realized in the system.")
|
"Set this flag to true if you would like tests to emit metrics, e.g. latency of resources being realized in the system.")
|
||||||
|
|
||||||
|
defaultRepo := os.Getenv("KO_DOCKER_REPO")
|
||||||
|
flag.StringVar(&f.DockerRepo, "dockerrepo", defaultRepo,
|
||||||
|
"Provide the uri of the docker repo you have uploaded the test image to using `uploadtestimage.sh`. Defaults to $KO_DOCKER_REPO")
|
||||||
|
|
||||||
|
flag.StringVar(&f.Tag, "tag", "e2e", "Provide the version tag for the test images.")
|
||||||
|
|
||||||
return &f
|
return &f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImagePath is a helper function to prefix image name with repo and suffix with tag
|
||||||
|
func ImagePath(name string) string {
|
||||||
|
return fmt.Sprintf("%s/%s:%s", Flags.DockerRepo, name, Flags.Tag)
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ package test
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/knative/pkg/test/logging"
|
"github.com/knative/pkg/test/logging"
|
||||||
|
@ -35,6 +36,7 @@ import (
|
||||||
const (
|
const (
|
||||||
interval = 1 * time.Second
|
interval = 1 * time.Second
|
||||||
podTimeout = 8 * time.Minute
|
podTimeout = 8 * time.Minute
|
||||||
|
logTimeout = 1 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
// WaitForDeploymentState polls the status of the Deployment called name
|
// WaitForDeploymentState polls the status of the Deployment called name
|
||||||
|
@ -78,9 +80,36 @@ func GetConfigMap(client *KubeClient, namespace string) k8styped.ConfigMapInterf
|
||||||
return client.Kube.CoreV1().ConfigMaps(namespace)
|
return client.Kube.CoreV1().ConfigMaps(namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a func that evaluates if a deployment has scaled to 0 pods
|
// DeploymentScaledToZeroFunc returns a func that evaluates if a deployment has scaled to 0 pods
|
||||||
func DeploymentScaledToZeroFunc() func(d *apiv1beta1.Deployment) (bool, error) {
|
func DeploymentScaledToZeroFunc() func(d *apiv1beta1.Deployment) (bool, error) {
|
||||||
return func(d *apiv1beta1.Deployment) (bool, error) {
|
return func(d *apiv1beta1.Deployment) (bool, error) {
|
||||||
return d.Status.ReadyReplicas == 0, nil
|
return d.Status.ReadyReplicas == 0, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitForLogContent waits until logs for given Pod/Container include the given content.
|
||||||
|
// If the content is not present within timeout it returns error.
|
||||||
|
func WaitForLogContent(client *KubeClient, podName, containerName, content string) error {
|
||||||
|
return wait.PollImmediate(interval, logTimeout, func() (bool, error) {
|
||||||
|
logs, err := client.PodLogs(podName, containerName)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return strings.Contains(string(logs), content), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForAllPodsRunning waits for all the pods to be in running state
|
||||||
|
func WaitForAllPodsRunning(client *KubeClient, namespace string) error {
|
||||||
|
return WaitForPodListState(client, PodsRunning, "PodsAreRunning", namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodsRunning will check the status conditions of the pod list and return true all pods are Running
|
||||||
|
func PodsRunning(podList *corev1.PodList) (bool, error) {
|
||||||
|
for _, pod := range podList.Items {
|
||||||
|
if pod.Status.Phase != corev1.PodRunning && pod.Status.Phase != corev1.PodSucceeded {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue