testcase.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package framework
  14. import (
  15. "time"
  16. //nolint
  17. "github.com/external-secrets/external-secrets-e2e/framework/log"
  18. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  19. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  20. . "github.com/onsi/ginkgo/v2"
  21. . "github.com/onsi/gomega"
  22. v1 "k8s.io/api/core/v1"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "sigs.k8s.io/controller-runtime/pkg/client"
  25. )
  26. var TargetSecretName = "target-secret"
  27. // TestCase contains the test infra to run a table driven test.
  28. type TestCase struct {
  29. Framework *Framework
  30. ExternalSecret *esv1.ExternalSecret
  31. PushSecret *esv1alpha1.PushSecret
  32. PushSecretSource *v1.Secret
  33. AdditionalObjects []client.Object
  34. Secrets map[string]SecretEntry
  35. ExpectedSecret *v1.Secret
  36. Prepare func(*TestCase, SecretStoreProvider)
  37. Cleanup func()
  38. ProviderOverride SecretStoreProvider
  39. AfterSync func(SecretStoreProvider, *v1.Secret)
  40. VerifyPushSecretOutcome func(ps *esv1alpha1.PushSecret, pushClient esv1.SecretsClient)
  41. }
  42. type SecretEntry struct {
  43. Value string
  44. Tags map[string]string
  45. }
  46. // SecretStoreProvider is a interface that must be implemented
  47. // by a provider that runs the e2e test.
  48. type SecretStoreProvider interface {
  49. CreateSecret(key string, val SecretEntry)
  50. DeleteSecret(key string)
  51. }
  52. // TableFuncWithExternalSecret returns the main func that runs a TestCase in a table driven test.
  53. func TableFuncWithExternalSecret(f *Framework, prov SecretStoreProvider) func(...func(*TestCase)) {
  54. return func(tweaks ...func(*TestCase)) {
  55. // make default test case
  56. // and apply customization to it
  57. tc := makeDefaultExternalSecretTestCase(f)
  58. for _, tweak := range tweaks {
  59. tweak(tc)
  60. }
  61. defer func() {
  62. if tc.Cleanup != nil {
  63. tc.Cleanup()
  64. }
  65. }()
  66. prov = prepareTestCase(tc, prov)
  67. // create secrets & defer delete
  68. var deferRemoveKeys []string
  69. for k, v := range tc.Secrets {
  70. key := k
  71. prov.CreateSecret(key, v)
  72. deferRemoveKeys = append(deferRemoveKeys, key)
  73. }
  74. defer func() {
  75. for _, k := range deferRemoveKeys {
  76. prov.DeleteSecret(k)
  77. }
  78. }()
  79. // create additional objects
  80. generateAdditionalObjects(tc)
  81. // create v1alpha1 external secret, if provided
  82. createProvidedExternalSecret(tc)
  83. // wait for Kind=Secret to have the expected data
  84. executeAfterSync(tc, f, prov)
  85. }
  86. }
  87. func executeAfterSync(tc *TestCase, f *Framework, prov SecretStoreProvider) {
  88. if tc.ExpectedSecret != nil {
  89. secret, err := tc.Framework.WaitForSecretValue(tc.Framework.Namespace.Name, externalSecretTargetName(tc), tc.ExpectedSecret)
  90. if err != nil {
  91. f.printESDebugLogs(tc.ExternalSecret.Name, tc.ExternalSecret.Namespace)
  92. log.Logf("Did not match. Expected: %+v, Got: %+v", tc.ExpectedSecret, secret)
  93. }
  94. Expect(err).ToNot(HaveOccurred())
  95. tc.AfterSync(prov, secret)
  96. } else {
  97. tc.AfterSync(prov, nil)
  98. }
  99. }
  100. func externalSecretTargetName(tc *TestCase) string {
  101. if tc == nil || tc.ExternalSecret == nil {
  102. return TargetSecretName
  103. }
  104. if tc.ExternalSecret.Spec.Target.Name != "" {
  105. return tc.ExternalSecret.Spec.Target.Name
  106. }
  107. if tc.ExternalSecret.Name != "" {
  108. return tc.ExternalSecret.Name
  109. }
  110. return TargetSecretName
  111. }
  112. func generateAdditionalObjects(tc *TestCase) {
  113. if tc.AdditionalObjects != nil {
  114. for _, obj := range tc.AdditionalObjects {
  115. err := tc.Framework.CRClient.Create(GinkgoT().Context(), obj)
  116. Expect(err).ToNot(HaveOccurred())
  117. }
  118. }
  119. }
  120. func createProvidedExternalSecret(tc *TestCase) {
  121. if tc.ExternalSecret == nil {
  122. return
  123. }
  124. err := tc.Framework.CRClient.Create(GinkgoT().Context(), tc.ExternalSecret)
  125. Expect(err).ToNot(HaveOccurred())
  126. }
  127. // TableFuncWithPushSecret returns the main func that runs a TestCase in a table driven test for push secrets.
  128. func TableFuncWithPushSecret(f *Framework, prov SecretStoreProvider, pushClient esv1.SecretsClient) func(...func(*TestCase)) {
  129. return func(tweaks ...func(*TestCase)) {
  130. var err error
  131. // make default test case
  132. // and apply customization to it
  133. tc := makeDefaultPushSecretTestCase(f)
  134. for _, tweak := range tweaks {
  135. tweak(tc)
  136. }
  137. prov = prepareTestCase(tc, prov)
  138. // additional objects
  139. generateAdditionalObjects(tc)
  140. if tc.PushSecretSource != nil {
  141. err := tc.Framework.CRClient.Create(GinkgoT().Context(), tc.PushSecretSource)
  142. Expect(err).ToNot(HaveOccurred())
  143. }
  144. // create v1alpha1 push secret, if provided
  145. if tc.PushSecret != nil {
  146. // create v1beta1 external secret otherwise
  147. err = tc.Framework.CRClient.Create(GinkgoT().Context(), tc.PushSecret)
  148. Expect(err).ToNot(HaveOccurred())
  149. }
  150. // Run verification on the secret that push secret created or not.
  151. tc.VerifyPushSecretOutcome(tc.PushSecret, pushClient)
  152. }
  153. }
  154. func prepareTestCase(tc *TestCase, prov SecretStoreProvider) SecretStoreProvider {
  155. prov = effectiveTestCaseProvider(tc, prov)
  156. if tc.Prepare != nil {
  157. tc.Prepare(tc, prov)
  158. }
  159. return effectiveTestCaseProvider(tc, prov)
  160. }
  161. func effectiveTestCaseProvider(tc *TestCase, prov SecretStoreProvider) SecretStoreProvider {
  162. if tc.ProviderOverride != nil {
  163. return tc.ProviderOverride
  164. }
  165. return prov
  166. }
  167. func makeDefaultExternalSecretTestCase(f *Framework) *TestCase {
  168. return &TestCase{
  169. AfterSync: func(ssp SecretStoreProvider, s *v1.Secret) {},
  170. Framework: f,
  171. ExternalSecret: &esv1.ExternalSecret{
  172. ObjectMeta: metav1.ObjectMeta{
  173. Name: "e2e-es",
  174. Namespace: f.Namespace.Name,
  175. },
  176. Spec: esv1.ExternalSecretSpec{
  177. RefreshInterval: &metav1.Duration{Duration: time.Second * 5},
  178. SecretStoreRef: esv1.SecretStoreRef{
  179. Name: f.Namespace.Name,
  180. Kind: f.DefaultSecretStoreRefKind,
  181. },
  182. Target: esv1.ExternalSecretTarget{
  183. Name: TargetSecretName,
  184. },
  185. },
  186. },
  187. }
  188. }
  189. func makeDefaultPushSecretTestCase(f *Framework) *TestCase {
  190. return &TestCase{
  191. Framework: f,
  192. PushSecret: &esv1alpha1.PushSecret{
  193. ObjectMeta: metav1.ObjectMeta{
  194. Name: "e2e-ps",
  195. Namespace: f.Namespace.Name,
  196. },
  197. Spec: esv1alpha1.PushSecretSpec{
  198. RefreshInterval: &metav1.Duration{Duration: time.Second * 5},
  199. SecretStoreRefs: []esv1alpha1.PushSecretStoreRef{
  200. {
  201. Name: f.Namespace.Name,
  202. Kind: f.DefaultPushSecretStoreRefKind,
  203. APIVersion: f.DefaultPushSecretStoreRefAPIVersion,
  204. },
  205. },
  206. },
  207. },
  208. }
  209. }