|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*
- Copyright 2021 The KubeEdge Authors.
- Copyright 2015 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 framework
-
- import (
- "context"
- "fmt"
- "strings"
-
- "github.com/onsi/ginkgo"
- "github.com/onsi/gomega"
- v1 "k8s.io/api/core/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- clientset "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/rest"
-
- sednaclientset "github.com/kubeedge/sedna/pkg/client/clientset/versioned"
- )
-
- // Framework supports common operations used by e2e tests; it will keep a client & a namespace for you.
- // Eventual goal is to merge this with integration test framework.
- type Framework struct {
- BaseName string
-
- // Set together with creating the ClientSet and the namespace.
- // Guaranteed to be unique in the cluster even when running the same
- // test multiple times in parallel.
- UniqueName string
-
- SednaClientSet sednaclientset.Interface
- ClientSet clientset.Interface
-
- SkipNamespaceCreation bool // Whether to skip creating a namespace
- Namespace *v1.Namespace // Every test has at least one namespace unless creation is skipped
- namespacesToDelete []*v1.Namespace // Some tests have more than one.
-
- // To make sure that this framework cleans up after itself, no matter what,
- // we install a Cleanup action before each test and clear it after. If we
- // should abort, the AfterSuite hook should run all Cleanup actions.
- cleanupHandle CleanupActionHandle
-
- // configuration for framework's client
- Options Options
-
- AfterEachActions []func()
- }
-
- // Options contains some options
- type Options struct {
- ClientQPS float32
- ClientBurst int
- GroupVersion *schema.GroupVersion
- }
-
- // NewDefaultFramework makes a new framework and sets up a BeforeEach/AfterEach for
- // you (you can write additional before/after each functions).
- func NewDefaultFramework(baseName string) *Framework {
- options := Options{
- ClientQPS: 20,
- ClientBurst: 50,
- }
- return NewFramework(baseName, options, nil)
- }
-
- // NewFramework makes a new framework and sets up a BeforeEach/AfterEach
- func NewFramework(baseName string, options Options, client clientset.Interface) *Framework {
- f := &Framework{
- BaseName: baseName,
- Options: options,
- ClientSet: client,
- }
-
- ginkgo.BeforeEach(f.BeforeEach)
- ginkgo.AfterEach(f.AfterEach)
-
- return f
- }
-
- // BeforeEach gets a client and makes a namespace.
- func (f *Framework) BeforeEach() {
- // The fact that we need this feels like a bug in ginkgo.
- // https://github.com/onsi/ginkgo/issues/222
- f.cleanupHandle = AddCleanupAction(f.AfterEach)
- if f.ClientSet == nil {
- ginkgo.By("Creating a kubernetes client")
- config, err := LoadConfig()
- gomega.Expect(err).NotTo(gomega.HaveOccurred())
- testDesc := ginkgo.CurrentGinkgoTestDescription()
- if len(testDesc.ComponentTexts) > 0 {
- componentTexts := strings.Join(testDesc.ComponentTexts, " ")
- config.UserAgent = fmt.Sprintf(
- "%v -- %v",
- rest.DefaultKubernetesUserAgent(),
- componentTexts)
- }
-
- config.QPS = f.Options.ClientQPS
- config.Burst = f.Options.ClientBurst
- if f.Options.GroupVersion != nil {
- config.GroupVersion = f.Options.GroupVersion
- }
-
- f.ClientSet, err = clientset.NewForConfig(config)
- gomega.Expect(err).NotTo(gomega.HaveOccurred())
-
- // sedna.io is based on CRD, which is served only as JSON
- jsonConfig := config
- jsonConfig.ContentType = "application/json"
- f.SednaClientSet, err = sednaclientset.NewForConfig(jsonConfig)
- gomega.Expect(err).NotTo(gomega.HaveOccurred())
- }
-
- if !f.SkipNamespaceCreation {
- ginkgo.By(fmt.Sprintf("Building a namespace api object, basename %s", f.BaseName))
- namespace, err := f.CreateNamespace(f.BaseName, map[string]string{
- "e2e-framework": f.BaseName,
- })
- gomega.Expect(err).NotTo(gomega.HaveOccurred())
-
- f.Namespace = namespace
-
- f.UniqueName = f.Namespace.GetName()
- } else {
- // not guaranteed to be unique, but very likely
- f.UniqueName = f.BaseName + "-" + RandomSuffix()
- }
- }
-
- // AfterEach deletes the namespace, after reading its events.
- func (f *Framework) AfterEach() {
- RemoveCleanupAction(f.cleanupHandle)
-
- // DeleteNamespace at the very end in defer, to avoid any
- // expectation failures preventing deleting the namespace.
- defer func() {
- nsDeletionErrors := map[string]error{}
- // Whether to delete namespace is determined by 3 factors: delete-namespace flag, delete-namespace-on-failure flag and the test result
- // if delete-namespace set to false, namespace will always be preserved.
- // if delete-namespace is true and delete-namespace-on-failure is false, namespace will be preserved if test failed.
- if TestContext.DeleteNamespace && (TestContext.DeleteNamespaceOnFailure || !ginkgo.CurrentGinkgoTestDescription().Failed) {
- for _, ns := range f.namespacesToDelete {
- ginkgo.By(fmt.Sprintf("Destroying namespace %q for this suite.", ns.Name))
- if err := f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), ns.Name, metav1.DeleteOptions{}); err != nil {
- if !apierrors.IsNotFound(err) {
- nsDeletionErrors[ns.Name] = err
- } else {
- Logf("Namespace %v was already deleted", ns.Name)
- }
- }
- }
- } else {
- if !TestContext.DeleteNamespace {
- Logf("Found DeleteNamespace=false, skipping namespace deletion!")
- } else {
- Logf("Found DeleteNamespaceOnFailure=false and current test failed, skipping namespace deletion!")
- }
- }
-
- // Paranoia-- prevent reuse!
- f.Namespace = nil
- f.SednaClientSet = nil
- f.ClientSet = nil
- f.namespacesToDelete = nil
-
- // if we had errors deleting, report them now.
- if len(nsDeletionErrors) != 0 {
- messages := []string{}
- for namespaceKey, namespaceErr := range nsDeletionErrors {
- messages = append(messages, fmt.Sprintf("Couldn't delete ns: %q: %s (%#v)", namespaceKey, namespaceErr, namespaceErr))
- }
- Fail(strings.Join(messages, ","))
- }
- }()
-
- for _, f := range f.AfterEachActions {
- f()
- }
- }
-
- // CreateNamespace is used to create namespace
- func (f *Framework) CreateNamespace(baseName string, labels map[string]string) (*v1.Namespace, error) {
- ns, err := CreateTestingNS(baseName, f.ClientSet, labels)
- // check ns instead of err to see if it's nil as we may
- // fail to create serviceAccount in it.
- f.AddNamespacesToDelete(ns)
-
- return ns, err
- }
-
- // AddNamespacesToDelete adds one or more namespaces to be deleted when the test
- // completes.
- func (f *Framework) AddNamespacesToDelete(namespaces ...*v1.Namespace) {
- for _, ns := range namespaces {
- if ns == nil {
- continue
- }
- f.namespacesToDelete = append(f.namespacesToDelete, ns)
- }
- }
|