eso_v2_mutators_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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 addon
  14. import (
  15. "regexp"
  16. "strconv"
  17. "testing"
  18. )
  19. func TestWithV2FakeProvider(t *testing.T) {
  20. t.Setenv("VERSION", "test-version")
  21. eso := NewESO(WithV2FakeProvider())
  22. assertV2ProviderBaseVars(t, eso.HelmChart)
  23. assertVarValue(t, eso.HelmChart, "providers.enabled", "true")
  24. assertProvider(
  25. t,
  26. eso.HelmChart,
  27. "fake",
  28. "fake",
  29. "ghcr.io/external-secrets/provider-fake",
  30. "test-version",
  31. )
  32. assertSequentialProviderIndexes(t, eso.HelmChart)
  33. providers := providerEntries(t, eso.HelmChart)
  34. if len(providers) != 1 {
  35. t.Fatalf("expected exactly one provider entry, got %d", len(providers))
  36. }
  37. if providers[0].Name != "fake" {
  38. t.Fatalf("expected fake to be at index 0 when standalone, got index 0 name %q", providers[0].Name)
  39. }
  40. }
  41. func TestWithV2AWSProvider(t *testing.T) {
  42. t.Setenv("VERSION", "test-version")
  43. eso := NewESO(WithV2AWSProvider())
  44. assertV2ProviderBaseVars(t, eso.HelmChart)
  45. assertVarValue(t, eso.HelmChart, "providers.enabled", "true")
  46. assertProvider(
  47. t,
  48. eso.HelmChart,
  49. "aws",
  50. "aws",
  51. "ghcr.io/external-secrets/provider-aws",
  52. "test-version",
  53. )
  54. assertSequentialProviderIndexes(t, eso.HelmChart)
  55. providers := providerEntries(t, eso.HelmChart)
  56. if len(providers) != 1 {
  57. t.Fatalf("expected exactly one provider entry, got %d", len(providers))
  58. }
  59. if providers[0].Name != "aws" {
  60. t.Fatalf("expected aws to be at index 0 when standalone, got index 0 name %q", providers[0].Name)
  61. }
  62. }
  63. func TestWithV2ProvidersComposeIncludesAWS(t *testing.T) {
  64. t.Setenv("VERSION", "test-version")
  65. eso := NewESO(
  66. WithV2Namespace(),
  67. WithV2KubernetesProvider(),
  68. WithV2FakeProvider(),
  69. WithV2AWSProvider(),
  70. )
  71. if eso.HelmChart.Namespace != v2HelmNamespace {
  72. t.Fatalf("expected namespace %q, got %q", v2HelmNamespace, eso.HelmChart.Namespace)
  73. }
  74. if eso.HelmChart.ReleaseName != v2HelmReleaseName {
  75. t.Fatalf("expected release name %q, got %q", v2HelmReleaseName, eso.HelmChart.ReleaseName)
  76. }
  77. if !containsArg(eso.HelmChart.Args, "--create-namespace") {
  78. t.Fatalf("expected --create-namespace arg, got %v", eso.HelmChart.Args)
  79. }
  80. assertV2ProviderBaseVars(t, eso.HelmChart)
  81. assertVarValue(t, eso.HelmChart, "providers.enabled", "true")
  82. assertProvider(
  83. t,
  84. eso.HelmChart,
  85. "kubernetes",
  86. "kubernetes",
  87. "ghcr.io/external-secrets/provider-kubernetes",
  88. "test-version",
  89. )
  90. assertProvider(
  91. t,
  92. eso.HelmChart,
  93. "fake",
  94. "fake",
  95. "ghcr.io/external-secrets/provider-fake",
  96. "test-version",
  97. )
  98. assertProvider(
  99. t,
  100. eso.HelmChart,
  101. "aws",
  102. "aws",
  103. "ghcr.io/external-secrets/provider-aws",
  104. "test-version",
  105. )
  106. assertSequentialProviderIndexes(t, eso.HelmChart)
  107. providers := providerEntries(t, eso.HelmChart)
  108. if providers[0].Name != "kubernetes" {
  109. t.Fatalf("expected kubernetes to remain first provider entry, got %q at index 0", providers[0].Name)
  110. }
  111. if providers[1].Name != "fake" {
  112. t.Fatalf("expected fake to be second provider entry, got %q at index 1", providers[1].Name)
  113. }
  114. if providers[2].Name != "aws" {
  115. t.Fatalf("expected aws to be third provider entry, got %q at index 2", providers[2].Name)
  116. }
  117. }
  118. func TestWithV2FakeProviderDoesNotDuplicateOnRepeat(t *testing.T) {
  119. t.Setenv("VERSION", "test-version")
  120. eso := NewESO(WithV2FakeProvider(), WithV2FakeProvider())
  121. providers := providerEntries(t, eso.HelmChart)
  122. if len(providers) != 1 {
  123. t.Fatalf("expected one provider entry after applying fake mutator twice, got %d", len(providers))
  124. }
  125. if providers[0].Name != "fake" {
  126. t.Fatalf("expected fake provider at index 0 after repeat application, got %q", providers[0].Name)
  127. }
  128. assertProvider(t, eso.HelmChart, "fake", "fake", "ghcr.io/external-secrets/provider-fake", "test-version")
  129. }
  130. func TestWithV2FakeProviderUpdatesExistingEntryInPlace(t *testing.T) {
  131. t.Setenv("VERSION", "test-version")
  132. eso := NewESO()
  133. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].name", Value: "fake"})
  134. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].type", Value: "fake"})
  135. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].enabled", Value: "false"})
  136. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].replicaCount", Value: "9"})
  137. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].image.repository", Value: "example.invalid/old-fake"})
  138. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].image.tag", Value: "old-tag"})
  139. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.list[3].image.pullPolicy", Value: "Always"})
  140. WithV2FakeProvider()(eso)
  141. providers := providerEntries(t, eso.HelmChart)
  142. if len(providers) != 1 {
  143. t.Fatalf("expected one fake provider entry after in-place update, got %d", len(providers))
  144. }
  145. if providers[3].Name != "fake" {
  146. t.Fatalf("expected fake provider to stay at index 3, got %q", providers[3].Name)
  147. }
  148. assertProvider(t, eso.HelmChart, "fake", "fake", "ghcr.io/external-secrets/provider-fake", "test-version")
  149. }
  150. func TestWithV2FakeProviderEnforcesRequiredFlags(t *testing.T) {
  151. t.Setenv("VERSION", "test-version")
  152. eso := NewESO()
  153. setOrAppendVar(eso.HelmChart, StringTuple{Key: "replicaCount", Value: "7"})
  154. setOrAppendVar(eso.HelmChart, StringTuple{Key: "v2.enabled", Value: "false"})
  155. setOrAppendVar(eso.HelmChart, StringTuple{Key: "crds.createClusterProviderClass", Value: "false"})
  156. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providers.enabled", Value: "false"})
  157. setOrAppendVar(eso.HelmChart, StringTuple{Key: "providerDefaults.replicaCount", Value: "8"})
  158. WithV2FakeProvider()(eso)
  159. assertVarValue(t, eso.HelmChart, "replicaCount", "7")
  160. assertVarValue(t, eso.HelmChart, "v2.enabled", "true")
  161. assertVarValue(t, eso.HelmChart, "crds.createClusterProviderClass", "true")
  162. assertVarValue(t, eso.HelmChart, "providers.enabled", "true")
  163. assertVarValue(t, eso.HelmChart, "providerDefaults.replicaCount", "8")
  164. }
  165. func TestWithV2ProviderServiceAccountOverridesAWSInPlace(t *testing.T) {
  166. t.Setenv("VERSION", "test-version")
  167. eso := NewESO(WithV2AWSProvider())
  168. WithV2ProviderServiceAccount("aws", "irsa-sa")(eso)
  169. assertVarValue(t, eso.HelmChart, "providers.list[0].serviceAccount.create", "false")
  170. assertVarValue(t, eso.HelmChart, "providers.list[0].serviceAccount.name", "irsa-sa")
  171. }
  172. func assertVarValue(t *testing.T, chart *HelmChart, key, wantValue string) {
  173. t.Helper()
  174. for _, variable := range chart.Vars {
  175. if variable.Key == key {
  176. if variable.Value != wantValue {
  177. t.Fatalf("expected %s=%s, got %s", key, wantValue, variable.Value)
  178. }
  179. return
  180. }
  181. }
  182. t.Fatalf("expected %s=%s to be set", key, wantValue)
  183. }
  184. func assertV2ProviderBaseVars(t *testing.T, chart *HelmChart) {
  185. t.Helper()
  186. assertVarValue(t, chart, "replicaCount", "1")
  187. assertVarValue(t, chart, "v2.enabled", "true")
  188. assertVarValue(t, chart, "crds.createClusterProviderClass", "true")
  189. assertVarValue(t, chart, "providerDefaults.replicaCount", "1")
  190. }
  191. func assertProvider(t *testing.T, chart *HelmChart, name, providerType, imageRepository, imageTag string) {
  192. t.Helper()
  193. for _, provider := range providerEntries(t, chart) {
  194. if provider.Name != name {
  195. continue
  196. }
  197. if provider.Type != providerType {
  198. t.Fatalf("expected provider %q to have type %q, got %q", name, providerType, provider.Type)
  199. }
  200. if provider.Enabled != "true" {
  201. t.Fatalf("expected provider %q to be enabled, got %q", name, provider.Enabled)
  202. }
  203. if provider.ReplicaCount != "1" {
  204. t.Fatalf("expected provider %q replicaCount 1, got %q", name, provider.ReplicaCount)
  205. }
  206. if provider.ImageRepository != imageRepository {
  207. t.Fatalf("expected provider %q image repository %q, got %q", name, imageRepository, provider.ImageRepository)
  208. }
  209. if provider.ImageTag != imageTag {
  210. t.Fatalf("expected provider %q image tag %q, got %q", name, imageTag, provider.ImageTag)
  211. }
  212. if provider.ImagePullPolicy != "IfNotPresent" {
  213. t.Fatalf("expected provider %q image pull policy IfNotPresent, got %q", name, provider.ImagePullPolicy)
  214. }
  215. return
  216. }
  217. t.Fatalf("expected provider %q to exist", name)
  218. }
  219. func assertSequentialProviderIndexes(t *testing.T, chart *HelmChart) {
  220. t.Helper()
  221. providers := providerEntries(t, chart)
  222. for i := 0; i < len(providers); i++ {
  223. if _, ok := providers[i]; !ok {
  224. t.Fatalf("expected provider index %d to exist, got indexes %v", i, sortedProviderIndexes(providers))
  225. }
  226. }
  227. }
  228. type providerEntry struct {
  229. Name string
  230. Type string
  231. Enabled string
  232. ReplicaCount string
  233. ImageRepository string
  234. ImageTag string
  235. ImagePullPolicy string
  236. }
  237. var providerVarPattern = regexp.MustCompile(`^providers\.list\[(\d+)\]\.(.+)$`)
  238. var allowedProviderFields = map[string]struct{}{
  239. "name": {},
  240. "type": {},
  241. "enabled": {},
  242. "replicaCount": {},
  243. "image.repository": {},
  244. "image.tag": {},
  245. "image.pullPolicy": {},
  246. }
  247. func providerEntries(t *testing.T, chart *HelmChart) map[int]providerEntry {
  248. t.Helper()
  249. providers := make(map[int]providerEntry)
  250. for _, variable := range chart.Vars {
  251. matches := providerVarPattern.FindStringSubmatch(variable.Key)
  252. if matches == nil {
  253. continue
  254. }
  255. index, err := strconv.Atoi(matches[1])
  256. if err != nil {
  257. t.Fatalf("unable to parse provider index from key %q: %v", variable.Key, err)
  258. }
  259. field := matches[2]
  260. if _, ok := allowedProviderFields[field]; !ok {
  261. t.Fatalf("unexpected provider field %q in key %q", field, variable.Key)
  262. }
  263. entry := providers[index]
  264. switch field {
  265. case "name":
  266. entry.Name = variable.Value
  267. case "type":
  268. entry.Type = variable.Value
  269. case "enabled":
  270. entry.Enabled = variable.Value
  271. case "replicaCount":
  272. entry.ReplicaCount = variable.Value
  273. case "image.repository":
  274. entry.ImageRepository = variable.Value
  275. case "image.tag":
  276. entry.ImageTag = variable.Value
  277. case "image.pullPolicy":
  278. entry.ImagePullPolicy = variable.Value
  279. }
  280. providers[index] = entry
  281. }
  282. return providers
  283. }
  284. func sortedProviderIndexes(providers map[int]providerEntry) []int {
  285. indexes := make([]int, 0, len(providers))
  286. for index := range providers {
  287. indexes = append(indexes, index)
  288. }
  289. for i := 0; i < len(indexes); i++ {
  290. for j := i + 1; j < len(indexes); j++ {
  291. if indexes[j] < indexes[i] {
  292. indexes[i], indexes[j] = indexes[j], indexes[i]
  293. }
  294. }
  295. }
  296. return indexes
  297. }