add integration test
This commit is contained in:
parent
2eb783bdbf
commit
e6a68178e9
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
ginkgo "github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
|
||||||
|
runtimeutils "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/component-base/logs"
|
||||||
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunE2ETests checks configuration parameters (specified through flags) and then runs
|
||||||
|
// E2E tests using the Ginkgo runner.
|
||||||
|
// If a "report directory" is specified, one or more JUnit test reports will be
|
||||||
|
// generated in this directory, and cluster logs will also be saved.
|
||||||
|
// This function is called on each Ginkgo node in parallel mode.
|
||||||
|
func RunE2ETests(t *testing.T) {
|
||||||
|
runtimeutils.ReallyCrash = true
|
||||||
|
logs.InitLogs()
|
||||||
|
defer logs.FlushLogs()
|
||||||
|
|
||||||
|
gomega.RegisterFailHandler(framework.Fail)
|
||||||
|
suiteConfig, _ := ginkgo.GinkgoConfiguration()
|
||||||
|
// Disable skipped tests unless they are explicitly requested.
|
||||||
|
if len(suiteConfig.FocusStrings) == 0 && len(suiteConfig.SkipStrings) == 0 {
|
||||||
|
suiteConfig.SkipStrings = []string{`\[Flaky\]|\[Feature:.+\]`}
|
||||||
|
}
|
||||||
|
ginkgo.RunSpecs(t, "Kubernetes e2e suite")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
"k8s.io/kubernetes/test/e2e/framework/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// handleFlags sets up all flags and parses the command line.
|
||||||
|
func handleFlags() {
|
||||||
|
config.CopyFlags(config.Flags, flag.CommandLine)
|
||||||
|
framework.RegisterCommonFlags(flag.CommandLine)
|
||||||
|
framework.RegisterClusterFlags(flag.CommandLine)
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// Register test flags, then parse flags.
|
||||||
|
handleFlags()
|
||||||
|
|
||||||
|
framework.AfterReadingAllFlags(&framework.TestContext)
|
||||||
|
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntegration(t *testing.T) {
|
||||||
|
RunE2ETests(t)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Kubernetes 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/autoscaler/vertical-pod-autoscaler/e2e/utils"
|
||||||
|
|
||||||
|
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
|
||||||
|
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
|
||||||
|
"k8s.io/autoscaler/vertical-pod-autoscaler/pkg/utils/test"
|
||||||
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
podsecurity "k8s.io/pod-security-admission/api"
|
||||||
|
|
||||||
|
ginkgo "github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = utils.RecommenderE2eDescribe("Flags", func() {
|
||||||
|
f := framework.NewDefaultFramework("vertical-pod-autoscaling")
|
||||||
|
f.NamespacePodSecurityEnforceLevel = podsecurity.LevelBaseline
|
||||||
|
|
||||||
|
var vpaClientSet vpa_clientset.Interface
|
||||||
|
var hamsterNamespace string
|
||||||
|
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
vpaClientSet = utils.GetVpaClientSet(f)
|
||||||
|
hamsterNamespace = f.Namespace.Name
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.AfterEach(func() {
|
||||||
|
f.ClientSet.AppsV1().Deployments(utils.RecommenderNamespace).Delete(context.TODO(), utils.RecommenderDeploymentName, metav1.DeleteOptions{})
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("--vpa-object-namespace", func() {
|
||||||
|
ginkgo.By("Setting up VPA deployment")
|
||||||
|
ignoredNamespace, err := f.CreateNamespace(context.TODO(), "ignored-namespace", nil)
|
||||||
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
f.Namespace.Name = utils.RecommenderNamespace
|
||||||
|
vpaDeployment := utils.NewVPADeployment(f, []string{
|
||||||
|
"--recommender-interval=10s",
|
||||||
|
fmt.Sprintf("--vpa-object-namespace=%s", hamsterNamespace),
|
||||||
|
})
|
||||||
|
utils.StartDeploymentPods(f, vpaDeployment)
|
||||||
|
|
||||||
|
testIncludedAndIgnoredNamespaces(f, vpaClientSet, hamsterNamespace, ignoredNamespace.Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("--ignored-vpa-object-namespaces", func() {
|
||||||
|
ginkgo.By("Setting up VPA deployment")
|
||||||
|
ignoredNamespace, err := f.CreateNamespace(context.TODO(), "ignored-namespace", nil)
|
||||||
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
f.Namespace.Name = utils.RecommenderNamespace
|
||||||
|
vpaDeployment := utils.NewVPADeployment(f, []string{
|
||||||
|
"--recommender-interval=10s",
|
||||||
|
fmt.Sprintf("--ignored-vpa-object-namespaces=%s", ignoredNamespace.Name),
|
||||||
|
})
|
||||||
|
utils.StartDeploymentPods(f, vpaDeployment)
|
||||||
|
|
||||||
|
testIncludedAndIgnoredNamespaces(f, vpaClientSet, hamsterNamespace, ignoredNamespace.Name)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create VPA and deployment in 2 namespaces, 1 should be ignored
|
||||||
|
// Ignored namespace VPA and deployment are intentionally created first
|
||||||
|
// so that by the time included namespace has recommendation generated,
|
||||||
|
// we know that ignored namespace has been waiting long enough.
|
||||||
|
func testIncludedAndIgnoredNamespaces(f *framework.Framework, vpaClientSet vpa_clientset.Interface, includedNamespace, ignoredNamespace string) {
|
||||||
|
ginkgo.By("Setting up a hamster deployment in ignored namespace")
|
||||||
|
f.Namespace.Name = ignoredNamespace
|
||||||
|
d := utils.NewNHamstersDeployment(f, 2)
|
||||||
|
_ = utils.StartDeploymentPods(f, d)
|
||||||
|
|
||||||
|
ginkgo.By("Setting up VPA for ignored namespace")
|
||||||
|
container1Name := utils.GetHamsterContainerNameByIndex(0)
|
||||||
|
container2Name := utils.GetHamsterContainerNameByIndex(1)
|
||||||
|
ignoredVpaCRD := test.VerticalPodAutoscaler().
|
||||||
|
WithName("hamster-vpa").
|
||||||
|
WithNamespace(ignoredNamespace).
|
||||||
|
WithTargetRef(utils.HamsterTargetRef).
|
||||||
|
WithContainer(container1Name).
|
||||||
|
WithScalingMode(container1Name, vpa_types.ContainerScalingModeOff).
|
||||||
|
WithContainer(container2Name).
|
||||||
|
Get()
|
||||||
|
f.Namespace.Name = ignoredNamespace
|
||||||
|
utils.InstallVPA(f, ignoredVpaCRD)
|
||||||
|
|
||||||
|
ginkgo.By("Setting up a hamster deployment in included namespace")
|
||||||
|
f.Namespace.Name = includedNamespace
|
||||||
|
d = utils.NewNHamstersDeployment(f, 2)
|
||||||
|
_ = utils.StartDeploymentPods(f, d)
|
||||||
|
|
||||||
|
ginkgo.By("Setting up VPA for included namespace")
|
||||||
|
vpaCRD := test.VerticalPodAutoscaler().
|
||||||
|
WithName("hamster-vpa").
|
||||||
|
WithNamespace(includedNamespace).
|
||||||
|
WithTargetRef(utils.HamsterTargetRef).
|
||||||
|
WithContainer(container1Name).
|
||||||
|
WithScalingMode(container1Name, vpa_types.ContainerScalingModeOff).
|
||||||
|
WithContainer(container2Name).
|
||||||
|
Get()
|
||||||
|
|
||||||
|
f.Namespace.Name = includedNamespace
|
||||||
|
utils.InstallVPA(f, vpaCRD)
|
||||||
|
|
||||||
|
ginkgo.By("Waiting for recommendation to be filled for just one container")
|
||||||
|
vpa, err := utils.WaitForRecommendationPresent(vpaClientSet, vpaCRD)
|
||||||
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
errMsg := fmt.Sprintf("%s container has recommendations turned off. We expect expect only recommendations for %s",
|
||||||
|
utils.GetHamsterContainerNameByIndex(0),
|
||||||
|
utils.GetHamsterContainerNameByIndex(1))
|
||||||
|
gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations).Should(gomega.HaveLen(1), errMsg)
|
||||||
|
gomega.Expect(vpa.Status.Recommendation.ContainerRecommendations[0].ContainerName).To(gomega.Equal(utils.GetHamsterContainerNameByIndex(1)), errMsg)
|
||||||
|
|
||||||
|
ginkgo.By("Ignored namespace should not be recommended")
|
||||||
|
ignoredVpa, err := vpaClientSet.AutoscalingV1().VerticalPodAutoscalers(ignoredNamespace).Get(context.TODO(), ignoredVpaCRD.Name, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
gomega.Expect(ignoredVpa.Status.Conditions).Should(gomega.HaveLen(0))
|
||||||
|
}
|
||||||
|
|
@ -31,10 +31,10 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
framework_deployment "k8s.io/kubernetes/test/e2e/framework/deployment"
|
||||||
|
|
||||||
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
|
vpa_types "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
|
||||||
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
|
vpa_clientset "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
|
||||||
framework_deployment "k8s.io/kubernetes/test/e2e/framework/deployment"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -145,6 +145,25 @@ func PatchVpaRecommendation(f *framework.Framework, vpa *vpa_types.VerticalPodAu
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to patch VPA.")
|
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to patch VPA.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewVPADeployment creates a VPA deployment with n containers
|
||||||
|
// for e2e test purposes.
|
||||||
|
func NewVPADeployment(f *framework.Framework, flags []string) *appsv1.Deployment {
|
||||||
|
d := framework_deployment.NewDeployment(
|
||||||
|
RecommenderDeploymentName, /*deploymentName*/
|
||||||
|
1, /*replicas*/
|
||||||
|
RecommenderLabels, /*podLabels*/
|
||||||
|
"recommender", /*imageName*/
|
||||||
|
"localhost:5001/vpa-recommender", /*image*/
|
||||||
|
appsv1.RollingUpdateDeploymentStrategyType, /*strategyType*/
|
||||||
|
)
|
||||||
|
d.ObjectMeta.Namespace = f.Namespace.Name
|
||||||
|
d.Spec.Template.Spec.Containers[0].ImagePullPolicy = apiv1.PullNever // Image must be loaded first
|
||||||
|
d.Spec.Template.Spec.ServiceAccountName = "vpa-recommender"
|
||||||
|
d.Spec.Template.Spec.Containers[0].Command = []string{"/recommender"}
|
||||||
|
d.Spec.Template.Spec.Containers[0].Args = flags
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
// NewNHamstersDeployment creates a simple hamster deployment with n containers
|
// NewNHamstersDeployment creates a simple hamster deployment with n containers
|
||||||
// for e2e test purposes.
|
// for e2e test purposes.
|
||||||
func NewNHamstersDeployment(f *framework.Framework, n int) *appsv1.Deployment {
|
func NewNHamstersDeployment(f *framework.Framework, n int) *appsv1.Deployment {
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,7 @@ The local test cases support running the `recommender` with external metrics. T
|
||||||
additional permissions we don't want to automatically enable for all customers via the
|
additional permissions we don't want to automatically enable for all customers via the
|
||||||
configuration given in `deploy/vpa-rbac.yaml`. The scripts use a context diff `hack/e2e/vpa-rbac.diff`
|
configuration given in `deploy/vpa-rbac.yaml`. The scripts use a context diff `hack/e2e/vpa-rbac.diff`
|
||||||
to enable those permission when running locally.
|
to enable those permission when running locally.
|
||||||
|
|
||||||
|
# Quick Integration Tests
|
||||||
|
|
||||||
|
`run-integration-locally.sh` is a quicker way to integration test compared to `run-e2e-locally.sh`. Only used for simple tests.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2025 The Kubernetes 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.
|
||||||
|
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
BASE_NAME=$(basename $0)
|
||||||
|
SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
|
||||||
|
source "${SCRIPT_ROOT}/hack/lib/util.sh"
|
||||||
|
|
||||||
|
ARCH=$(kube::util::host_arch)
|
||||||
|
|
||||||
|
function print_help {
|
||||||
|
echo "ERROR! Usage: $BASE_NAME <suite>"
|
||||||
|
echo "<suite> should be one of:"
|
||||||
|
echo " - recommender"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
print_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
print_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUITE=$1
|
||||||
|
REQUIRED_COMMANDS="
|
||||||
|
docker
|
||||||
|
go
|
||||||
|
kind
|
||||||
|
kubectl
|
||||||
|
make
|
||||||
|
"
|
||||||
|
|
||||||
|
for i in $REQUIRED_COMMANDS; do
|
||||||
|
if ! command -v $i > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "$i could not be found, please ensure it is installed"
|
||||||
|
echo
|
||||||
|
echo "The following commands are required to run these tests:"
|
||||||
|
echo $REQUIRED_COMMANDS
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! docker ps >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "docker isn't running"
|
||||||
|
echo
|
||||||
|
echo "Please ensure that docker is running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case ${SUITE} in
|
||||||
|
recommender)
|
||||||
|
COMPONENTS="${SUITE}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Deleting KIND cluster 'kind'."
|
||||||
|
kind delete cluster -n kind -q
|
||||||
|
|
||||||
|
echo "Creating KIND cluster 'kind'"
|
||||||
|
KIND_VERSION="kindest/node:v1.33.0@sha256:02f73d6ae3f11ad5d543f16736a2cb2a63a300ad60e81dac22099b0b04784a4e"
|
||||||
|
if ! kind create cluster --image=${KIND_VERSION}; then
|
||||||
|
echo "Failed to create KIND cluster. Exiting. Make sure kind version is updated."
|
||||||
|
echo "Available versions: https://github.com/kubernetes-sigs/kind/releases"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Local KIND images
|
||||||
|
export REGISTRY=${REGISTRY:-localhost:5001}
|
||||||
|
export TAG=${TAG:-latest}
|
||||||
|
|
||||||
|
rm -f ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml
|
||||||
|
patch -c ${SCRIPT_ROOT}/deploy/vpa-rbac.yaml -i ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.diff -o ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml
|
||||||
|
kubectl apply -f ${SCRIPT_ROOT}/hack/e2e/vpa-rbac.yaml
|
||||||
|
# Other-versioned CRDs are irrelevant as we're running a modern-ish cluster.
|
||||||
|
kubectl apply -f ${SCRIPT_ROOT}/deploy/vpa-v1-crd-gen.yaml
|
||||||
|
kubectl apply -f ${SCRIPT_ROOT}/hack/e2e/k8s-metrics-server.yaml
|
||||||
|
|
||||||
|
for i in ${COMPONENTS}; do
|
||||||
|
ALL_ARCHITECTURES=${ARCH} make --directory ${SCRIPT_ROOT}/pkg/${i} docker-build REGISTRY=${REGISTRY} TAG=${TAG}
|
||||||
|
docker tag ${REGISTRY}/vpa-${i}-${ARCH}:${TAG} ${REGISTRY}/vpa-${i}:${TAG}
|
||||||
|
kind load docker-image ${REGISTRY}/vpa-${i}:${TAG}
|
||||||
|
done
|
||||||
|
|
||||||
|
export GO111MODULE=on
|
||||||
|
|
||||||
|
case ${SUITE} in
|
||||||
|
recommender)
|
||||||
|
|
||||||
|
export KUBECONFIG=$HOME/.kube/config
|
||||||
|
pushd ${SCRIPT_ROOT}/e2e
|
||||||
|
go test ./integration/*go -v --test.timeout=10m --args --ginkgo.v=true --ginkgo.focus="\[VPA\] \[${SUITE}\]" --disable-log-dump --ginkgo.timeout=10m
|
||||||
|
INTEGRATION_RESULT=$?
|
||||||
|
popd
|
||||||
|
echo integration test result: ${INTEGRATION_RESULT}
|
||||||
|
if [ $INTEGRATION_RESULT -gt 0 ]; then
|
||||||
|
echo "Please check integration \"go test\" logs!"
|
||||||
|
fi
|
||||||
|
if [ $INTEGRATION_RESULT -gt 0 ]; then
|
||||||
|
echo "Tests failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Loading…
Reference in New Issue