You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

framework.go 7.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. Copyright 2021 The KubeEdge Authors.
  3. Copyright 2015 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package framework
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "github.com/onsi/ginkgo"
  20. "github.com/onsi/gomega"
  21. v1 "k8s.io/api/core/v1"
  22. apierrors "k8s.io/apimachinery/pkg/api/errors"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/runtime/schema"
  25. clientset "k8s.io/client-go/kubernetes"
  26. "k8s.io/client-go/rest"
  27. sednaclientset "github.com/kubeedge/sedna/pkg/client/clientset/versioned"
  28. )
  29. // Framework supports common operations used by e2e tests; it will keep a client & a namespace for you.
  30. // Eventual goal is to merge this with integration test framework.
  31. type Framework struct {
  32. BaseName string
  33. // Set together with creating the ClientSet and the namespace.
  34. // Guaranteed to be unique in the cluster even when running the same
  35. // test multiple times in parallel.
  36. UniqueName string
  37. SednaClientSet sednaclientset.Interface
  38. ClientSet clientset.Interface
  39. SkipNamespaceCreation bool // Whether to skip creating a namespace
  40. Namespace *v1.Namespace // Every test has at least one namespace unless creation is skipped
  41. namespacesToDelete []*v1.Namespace // Some tests have more than one.
  42. // To make sure that this framework cleans up after itself, no matter what,
  43. // we install a Cleanup action before each test and clear it after. If we
  44. // should abort, the AfterSuite hook should run all Cleanup actions.
  45. cleanupHandle CleanupActionHandle
  46. // configuration for framework's client
  47. Options Options
  48. AfterEachActions []func()
  49. }
  50. // Options contains some options
  51. type Options struct {
  52. ClientQPS float32
  53. ClientBurst int
  54. GroupVersion *schema.GroupVersion
  55. }
  56. // NewDefaultFramework makes a new framework and sets up a BeforeEach/AfterEach for
  57. // you (you can write additional before/after each functions).
  58. func NewDefaultFramework(baseName string) *Framework {
  59. options := Options{
  60. ClientQPS: 20,
  61. ClientBurst: 50,
  62. }
  63. return NewFramework(baseName, options, nil)
  64. }
  65. // NewFramework makes a new framework and sets up a BeforeEach/AfterEach
  66. func NewFramework(baseName string, options Options, client clientset.Interface) *Framework {
  67. f := &Framework{
  68. BaseName: baseName,
  69. Options: options,
  70. ClientSet: client,
  71. }
  72. ginkgo.BeforeEach(f.BeforeEach)
  73. ginkgo.AfterEach(f.AfterEach)
  74. return f
  75. }
  76. // BeforeEach gets a client and makes a namespace.
  77. func (f *Framework) BeforeEach() {
  78. // The fact that we need this feels like a bug in ginkgo.
  79. // https://github.com/onsi/ginkgo/issues/222
  80. f.cleanupHandle = AddCleanupAction(f.AfterEach)
  81. if f.ClientSet == nil {
  82. ginkgo.By("Creating a kubernetes client")
  83. config, err := LoadConfig()
  84. gomega.Expect(err).NotTo(gomega.HaveOccurred())
  85. testDesc := ginkgo.CurrentGinkgoTestDescription()
  86. if len(testDesc.ComponentTexts) > 0 {
  87. componentTexts := strings.Join(testDesc.ComponentTexts, " ")
  88. config.UserAgent = fmt.Sprintf(
  89. "%v -- %v",
  90. rest.DefaultKubernetesUserAgent(),
  91. componentTexts)
  92. }
  93. config.QPS = f.Options.ClientQPS
  94. config.Burst = f.Options.ClientBurst
  95. if f.Options.GroupVersion != nil {
  96. config.GroupVersion = f.Options.GroupVersion
  97. }
  98. f.ClientSet, err = clientset.NewForConfig(config)
  99. gomega.Expect(err).NotTo(gomega.HaveOccurred())
  100. // sedna.io is based on CRD, which is served only as JSON
  101. jsonConfig := config
  102. jsonConfig.ContentType = "application/json"
  103. f.SednaClientSet, err = sednaclientset.NewForConfig(jsonConfig)
  104. gomega.Expect(err).NotTo(gomega.HaveOccurred())
  105. }
  106. if !f.SkipNamespaceCreation {
  107. ginkgo.By(fmt.Sprintf("Building a namespace api object, basename %s", f.BaseName))
  108. namespace, err := f.CreateNamespace(f.BaseName, map[string]string{
  109. "e2e-framework": f.BaseName,
  110. })
  111. gomega.Expect(err).NotTo(gomega.HaveOccurred())
  112. f.Namespace = namespace
  113. f.UniqueName = f.Namespace.GetName()
  114. } else {
  115. // not guaranteed to be unique, but very likely
  116. f.UniqueName = f.BaseName + "-" + RandomSuffix()
  117. }
  118. }
  119. // AfterEach deletes the namespace, after reading its events.
  120. func (f *Framework) AfterEach() {
  121. RemoveCleanupAction(f.cleanupHandle)
  122. // DeleteNamespace at the very end in defer, to avoid any
  123. // expectation failures preventing deleting the namespace.
  124. defer func() {
  125. nsDeletionErrors := map[string]error{}
  126. // Whether to delete namespace is determined by 3 factors: delete-namespace flag, delete-namespace-on-failure flag and the test result
  127. // if delete-namespace set to false, namespace will always be preserved.
  128. // if delete-namespace is true and delete-namespace-on-failure is false, namespace will be preserved if test failed.
  129. if TestContext.DeleteNamespace && (TestContext.DeleteNamespaceOnFailure || !ginkgo.CurrentGinkgoTestDescription().Failed) {
  130. for _, ns := range f.namespacesToDelete {
  131. ginkgo.By(fmt.Sprintf("Destroying namespace %q for this suite.", ns.Name))
  132. if err := f.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), ns.Name, metav1.DeleteOptions{}); err != nil {
  133. if !apierrors.IsNotFound(err) {
  134. nsDeletionErrors[ns.Name] = err
  135. } else {
  136. Logf("Namespace %v was already deleted", ns.Name)
  137. }
  138. }
  139. }
  140. } else {
  141. if !TestContext.DeleteNamespace {
  142. Logf("Found DeleteNamespace=false, skipping namespace deletion!")
  143. } else {
  144. Logf("Found DeleteNamespaceOnFailure=false and current test failed, skipping namespace deletion!")
  145. }
  146. }
  147. // Paranoia-- prevent reuse!
  148. f.Namespace = nil
  149. f.SednaClientSet = nil
  150. f.ClientSet = nil
  151. f.namespacesToDelete = nil
  152. // if we had errors deleting, report them now.
  153. if len(nsDeletionErrors) != 0 {
  154. messages := []string{}
  155. for namespaceKey, namespaceErr := range nsDeletionErrors {
  156. messages = append(messages, fmt.Sprintf("Couldn't delete ns: %q: %s (%#v)", namespaceKey, namespaceErr, namespaceErr))
  157. }
  158. Fail(strings.Join(messages, ","))
  159. }
  160. }()
  161. for _, f := range f.AfterEachActions {
  162. f()
  163. }
  164. }
  165. // CreateNamespace is used to create namespace
  166. func (f *Framework) CreateNamespace(baseName string, labels map[string]string) (*v1.Namespace, error) {
  167. ns, err := CreateTestingNS(baseName, f.ClientSet, labels)
  168. // check ns instead of err to see if it's nil as we may
  169. // fail to create serviceAccount in it.
  170. f.AddNamespacesToDelete(ns)
  171. return ns, err
  172. }
  173. // AddNamespacesToDelete adds one or more namespaces to be deleted when the test
  174. // completes.
  175. func (f *Framework) AddNamespacesToDelete(namespaces ...*v1.Namespace) {
  176. for _, ns := range namespaces {
  177. if ns == nil {
  178. continue
  179. }
  180. f.namespacesToDelete = append(f.namespacesToDelete, ns)
  181. }
  182. }