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

patch_test.go 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package kubernetes
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/assert"
  5. "gopkg.in/yaml.v2"
  6. "github.com/fluxcd/flux/cluster/kubernetes/resource"
  7. )
  8. func TestPatchAndApply(t *testing.T) {
  9. for _, entry := range []struct {
  10. original string
  11. modified string
  12. }{
  13. { // unmodified
  14. original: `apiVersion: v1
  15. kind: Namespace
  16. metadata:
  17. name: namespace
  18. `,
  19. modified: `apiVersion: v1
  20. kind: Namespace
  21. metadata:
  22. name: namespace
  23. `,
  24. },
  25. {
  26. original: `apiVersion: flux.weave.works/v1beta1
  27. kind: HelmRelease
  28. metadata:
  29. name: ghost
  30. namespace: demo
  31. annotations:
  32. flux.weave.works/automated: "false"
  33. flux.weave.works/tag.chart-image: glob:1.21.*
  34. spec:
  35. values:
  36. image: bitnami/ghost
  37. tag: 1.21.5-r0
  38. `,
  39. modified: `apiVersion: flux.weave.works/v1beta1
  40. kind: HelmRelease
  41. metadata:
  42. name: ghost
  43. namespace: demo
  44. annotations:
  45. flux.weave.works/automated: "false"
  46. flux.weave.works/tag.chart-image: glob:1.21.*
  47. spec:
  48. values:
  49. image: bitnami/ghost
  50. tag: 1.21.6
  51. `,
  52. },
  53. {
  54. original: `apiVersion: flux.weave.works/v1beta1
  55. kind: HelmRelease
  56. metadata:
  57. name: name
  58. namespace: namespace
  59. annotations:
  60. flux.weave.works/tag.container: glob:1.4.*
  61. spec:
  62. values:
  63. container:
  64. image:
  65. repository: stefanprodan/podinfo
  66. tag: 1.4.4
  67. `,
  68. modified: `apiVersion: flux.weave.works/v1beta1
  69. kind: HelmRelease
  70. metadata:
  71. name: name
  72. namespace: namespace
  73. annotations:
  74. flux.weave.works/tag.container: glob:1.4.*
  75. spec:
  76. values:
  77. container:
  78. image:
  79. repository: stefanprodan/podinfo
  80. tag: 1.6
  81. `,
  82. },
  83. {
  84. original: `apiVersion: apps/v1
  85. kind: Deployment
  86. metadata:
  87. name: name
  88. spec:
  89. template:
  90. spec:
  91. containers:
  92. - name: one
  93. image: one:one
  94. - name: two
  95. image: two:two
  96. initContainers:
  97. - name: one
  98. image: one:one
  99. `,
  100. modified: `apiVersion: apps/v1
  101. kind: Deployment
  102. metadata:
  103. name: name
  104. spec:
  105. template:
  106. spec:
  107. containers:
  108. - name: one
  109. image: oneplus:oneplus
  110. - name: two
  111. image: two:two
  112. initContainers:
  113. - name: one
  114. image: one:one
  115. `,
  116. },
  117. {
  118. original: `apiVersion: apps/v1
  119. kind: Deployment
  120. metadata:
  121. name: name
  122. spec:
  123. template:
  124. spec:
  125. containers:
  126. - name: one
  127. image: one:one
  128. `,
  129. modified: `apiVersion: apps/v1
  130. kind: Deployment
  131. metadata:
  132. name: name
  133. annotations:
  134. flux.weave.works/locked: "true"
  135. spec:
  136. template:
  137. spec:
  138. containers:
  139. - name: one
  140. image: oneplus:oneplus
  141. `,
  142. },
  143. {
  144. original: `apiVersion: flux.weave.works/v1beta1
  145. kind: HelmRelease
  146. metadata:
  147. name: ghost
  148. namespace: demo
  149. annotations:
  150. flux.weave.works/automated: "false"
  151. flux.weave.works/tag.chart-image: glob:1.21.*
  152. spec:
  153. values:
  154. image: bitnami/ghost
  155. tag: 1.21.5-r0
  156. `,
  157. modified: `apiVersion: flux.weave.works/v1beta1
  158. kind: HelmRelease
  159. metadata:
  160. name: ghost
  161. namespace: demo
  162. annotations:
  163. flux.weave.works/automated: "true"
  164. spec:
  165. values:
  166. image: bitnami/ghost
  167. tag: 1.21.6
  168. `,
  169. },
  170. { // multiple documents
  171. original: `apiVersion: v1
  172. kind: Namespace
  173. metadata:
  174. name: namespace
  175. ---
  176. apiVersion: apps/v1
  177. kind: Deployment
  178. metadata:
  179. name: name
  180. spec:
  181. template:
  182. spec:
  183. containers:
  184. - name: one
  185. image: one:one
  186. ---
  187. apiVersion: flux.weave.works/v1beta1
  188. kind: HelmRelease
  189. metadata:
  190. name: ghost
  191. namespace: demo
  192. annotations:
  193. flux.weave.works/automated: "false"
  194. flux.weave.works/tag.chart-image: glob:1.21.*
  195. spec:
  196. values:
  197. image: bitnami/ghost
  198. tag: 1.21.5-r0
  199. `,
  200. modified: `apiVersion: flux.weave.works/v1beta1
  201. kind: HelmRelease
  202. metadata:
  203. name: ghost
  204. namespace: demo
  205. annotations:
  206. flux.weave.works/automated: "true"
  207. spec:
  208. values:
  209. image: bitnami/ghost
  210. tag: 1.21.6
  211. ---
  212. apiVersion: v1
  213. kind: Namespace
  214. metadata:
  215. name: namespace
  216. ---
  217. apiVersion: apps/v1
  218. kind: Deployment
  219. metadata:
  220. name: name
  221. annotations:
  222. flux.weave.works/locked: "true"
  223. spec:
  224. template:
  225. spec:
  226. containers:
  227. - name: one
  228. image: oneplus:oneplus
  229. `,
  230. },
  231. } {
  232. // Make sure creating the patch works
  233. patch, err := createManifestPatch([]byte(entry.original), []byte(entry.modified), "original", "updated")
  234. assert.NoError(t, err, "original:\n%s\n\nupdated:\n%s", entry.original, entry.modified)
  235. // Make sure that when applying the patch to the original manifest, we obtain the updated manifest
  236. patched, err := applyManifestPatch([]byte(entry.original), patch, "original", "patch")
  237. assert.NoError(t, err)
  238. expected, err := resource.ParseMultidoc([]byte(entry.modified), "updated")
  239. assert.NoError(t, err)
  240. actual, err := resource.ParseMultidoc(patched, "patched")
  241. assert.NoError(t, err)
  242. assert.Equal(t, len(actual), len(expected), "updated:\n%s\n\npatched:\n%s", entry.modified, string(patched))
  243. for id, expectedManifest := range expected {
  244. actualManifest, ok := actual[id]
  245. assert.True(t, ok, "resource %s missing in patched document stream", id)
  246. equalYAML(t, string(expectedManifest.Bytes()), string(actualManifest.Bytes()))
  247. }
  248. }
  249. }
  250. func equalYAML(t *testing.T, expected, actual string) {
  251. var obj1, obj2 interface{}
  252. err := yaml.Unmarshal([]byte(expected), &obj1)
  253. assert.NoError(t, err)
  254. err = yaml.Unmarshal([]byte(actual), &obj2)
  255. assert.NoError(t, err)
  256. assert.Equal(t, obj1, obj2, "expected:\n%s\n\nactual:\n%s", expected, actual)
  257. }