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.

load_test.go 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package resource
  2. import (
  3. "bytes"
  4. "path/filepath"
  5. "reflect"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/fluxcd/flux/cluster/kubernetes/testfiles"
  9. "github.com/fluxcd/flux/resource"
  10. )
  11. // for convenience
  12. func base(source, kind, namespace, name string) baseObject {
  13. b := baseObject{source: source, Kind: kind}
  14. b.Meta.Namespace = namespace
  15. b.Meta.Name = name
  16. return b
  17. }
  18. func TestParseEmpty(t *testing.T) {
  19. doc := ``
  20. objs, err := ParseMultidoc([]byte(doc), "test")
  21. if err != nil {
  22. t.Error(err)
  23. }
  24. if len(objs) != 0 {
  25. t.Errorf("expected empty set; got %#v", objs)
  26. }
  27. }
  28. func TestParseSome(t *testing.T) {
  29. docs := `---
  30. kind: Deployment
  31. metadata:
  32. name: b-deployment
  33. namespace: b-namespace
  34. ---
  35. kind: Deployment
  36. metadata:
  37. name: a-deployment
  38. `
  39. objs, err := ParseMultidoc([]byte(docs), "test")
  40. if err != nil {
  41. t.Error(err)
  42. }
  43. objA := base("test", "Deployment", "", "a-deployment")
  44. objB := base("test", "Deployment", "b-namespace", "b-deployment")
  45. expected := map[string]resource.Resource{
  46. objA.ResourceID().String(): &Deployment{baseObject: objA},
  47. objB.ResourceID().String(): &Deployment{baseObject: objB},
  48. }
  49. for id, obj := range expected {
  50. // Remove the bytes, so we can compare
  51. if !reflect.DeepEqual(obj, debyte(objs[id])) {
  52. t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
  53. }
  54. }
  55. }
  56. func TestParseSomeWithComment(t *testing.T) {
  57. docs := `# some random comment
  58. ---
  59. kind: Deployment
  60. metadata:
  61. name: b-deployment
  62. namespace: b-namespace
  63. ---
  64. kind: Deployment
  65. metadata:
  66. name: a-deployment
  67. `
  68. objs, err := ParseMultidoc([]byte(docs), "test")
  69. if err != nil {
  70. t.Error(err)
  71. }
  72. objA := base("test", "Deployment", "", "a-deployment")
  73. objB := base("test", "Deployment", "b-namespace", "b-deployment")
  74. expected := map[string]resource.Resource{
  75. objA.ResourceID().String(): &Deployment{baseObject: objA},
  76. objB.ResourceID().String(): &Deployment{baseObject: objB},
  77. }
  78. expectedL := len(expected)
  79. if len(objs) != expectedL {
  80. t.Errorf("expected %d objects from yaml source\n%s\n, got result: %d", expectedL, docs, len(objs))
  81. }
  82. for id, obj := range expected {
  83. // Remove the bytes, so we can compare
  84. if !reflect.DeepEqual(obj, debyte(objs[id])) {
  85. t.Errorf("At %+v expected:\n%#v\ngot:\n%#v", id, obj, objs[id])
  86. }
  87. }
  88. }
  89. func TestParseSomeLong(t *testing.T) {
  90. doc := `---
  91. kind: ConfigMap
  92. metadata:
  93. name: bigmap
  94. data:
  95. bigdata: |
  96. `
  97. buffer := bytes.NewBufferString(doc)
  98. line := " The quick brown fox jumps over the lazy dog.\n"
  99. for buffer.Len()+len(line) < 1024*1024 {
  100. buffer.WriteString(line)
  101. }
  102. _, err := ParseMultidoc(buffer.Bytes(), "test")
  103. if err != nil {
  104. t.Error(err)
  105. }
  106. }
  107. func TestParseBoundaryMarkers(t *testing.T) {
  108. doc := `---
  109. kind: ConfigMap
  110. metadata:
  111. name: bigmap
  112. ---
  113. ...
  114. ---
  115. ...
  116. ---
  117. ...
  118. ---
  119. ...
  120. `
  121. buffer := bytes.NewBufferString(doc)
  122. resources, err := ParseMultidoc(buffer.Bytes(), "test")
  123. assert.NoError(t, err)
  124. assert.Len(t, resources, 1)
  125. }
  126. func TestParseError(t *testing.T) {
  127. doc := `---
  128. kind: ConfigMap
  129. metadata:
  130. name: bigmap # contains a tab at the beginning
  131. `
  132. buffer := bytes.NewBufferString(doc)
  133. _, err := ParseMultidoc(buffer.Bytes(), "test")
  134. assert.Error(t, err)
  135. }
  136. func TestParseCronJob(t *testing.T) {
  137. doc := `---
  138. apiVersion: batch/v1beta1
  139. kind: CronJob
  140. metadata:
  141. namespace: default
  142. name: weekly-curl-homepage
  143. spec:
  144. jobTemplate:
  145. spec:
  146. template:
  147. spec:
  148. containers:
  149. - name: weekly-curl-homepage
  150. image: centos:7 # Has curl installed by default
  151. `
  152. objs, err := ParseMultidoc([]byte(doc), "test")
  153. assert.NoError(t, err)
  154. obj, ok := objs["default:cronjob/weekly-curl-homepage"]
  155. assert.True(t, ok)
  156. cj, ok := obj.(*CronJob)
  157. assert.True(t, ok)
  158. containers := cj.Spec.JobTemplate.Spec.Template.Spec.Containers
  159. if assert.Len(t, containers, 1) {
  160. assert.Equal(t, "centos:7", containers[0].Image)
  161. assert.Equal(t, "weekly-curl-homepage", containers[0].Name)
  162. }
  163. }
  164. func TestUnmarshalList(t *testing.T) {
  165. doc := `---
  166. kind: List
  167. metadata:
  168. name: list
  169. items:
  170. - kind: Deployment
  171. metadata:
  172. name: foo
  173. namespace: ns
  174. - kind: Service
  175. metadata:
  176. name: bar
  177. namespace: ns
  178. `
  179. res, err := unmarshalObject("", []byte(doc))
  180. if err != nil {
  181. t.Fatal(err)
  182. }
  183. list, ok := res.(*List)
  184. if !ok {
  185. t.Fatal("did not parse as a list")
  186. }
  187. if len(list.Items) != 2 {
  188. t.Fatalf("expected two items, got %+v", list.Items)
  189. }
  190. for i, id := range []resource.ID{
  191. resource.MustParseID("ns:deployment/foo"),
  192. resource.MustParseID("ns:service/bar")} {
  193. if list.Items[i].ResourceID() != id {
  194. t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
  195. }
  196. }
  197. }
  198. func TestUnmarshalDeploymentList(t *testing.T) {
  199. doc := `---
  200. kind: DeploymentList
  201. metadata:
  202. name: list
  203. items:
  204. - kind: Deployment
  205. metadata:
  206. name: foo
  207. namespace: ns
  208. - kind: Deployment
  209. metadata:
  210. name: bar
  211. namespace: ns
  212. `
  213. res, err := unmarshalObject("", []byte(doc))
  214. if err != nil {
  215. t.Fatal(err)
  216. }
  217. list, ok := res.(*List)
  218. if !ok {
  219. t.Fatal("did not parse as a list")
  220. }
  221. if len(list.Items) != 2 {
  222. t.Fatalf("expected two items, got %+v", list.Items)
  223. }
  224. for i, id := range []resource.ID{
  225. resource.MustParseID("ns:deployment/foo"),
  226. resource.MustParseID("ns:deployment/bar")} {
  227. if list.Items[i].ResourceID() != id {
  228. t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
  229. }
  230. }
  231. }
  232. func debyte(r resource.Resource) resource.Resource {
  233. if res, ok := r.(interface {
  234. debyte()
  235. }); ok {
  236. res.debyte()
  237. }
  238. return r
  239. }
  240. func TestLoadSome(t *testing.T) {
  241. dir, cleanup := testfiles.TempDir(t)
  242. defer cleanup()
  243. if err := testfiles.WriteTestFiles(dir); err != nil {
  244. t.Fatal(err)
  245. }
  246. objs, err := Load(dir, []string{dir})
  247. if err != nil {
  248. t.Error(err)
  249. }
  250. if len(objs) != len(testfiles.ResourceMap) {
  251. t.Errorf("expected %d objects from %d files, got result:\n%#v", len(testfiles.ResourceMap), len(testfiles.Files), objs)
  252. }
  253. }
  254. func TestChartTracker(t *testing.T) {
  255. dir, cleanup := testfiles.TempDir(t)
  256. defer cleanup()
  257. if err := testfiles.WriteTestFiles(dir); err != nil {
  258. t.Fatal(err)
  259. }
  260. ct, err := newChartTracker(dir)
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. noncharts := []string{"garbage", "locked-service-deploy.yaml",
  265. "test", "test/test-service-deploy.yaml"}
  266. for _, f := range noncharts {
  267. fq := filepath.Join(dir, f)
  268. if ct.isDirChart(fq) {
  269. t.Errorf("%q thought to be a chart", f)
  270. }
  271. if f == "garbage" {
  272. continue
  273. }
  274. if m, err := Load(dir, []string{fq}); err != nil || len(m) == 0 {
  275. t.Errorf("Load returned 0 objs, err=%v", err)
  276. }
  277. }
  278. if !ct.isDirChart(filepath.Join(dir, "charts/nginx")) {
  279. t.Errorf("charts/nginx not recognized as chart")
  280. }
  281. if !ct.isPathInChart(filepath.Join(dir, "charts/nginx/Chart.yaml")) {
  282. t.Errorf("charts/nginx/Chart.yaml not recognized as in chart")
  283. }
  284. chartfiles := []string{"charts",
  285. "charts/nginx",
  286. "charts/nginx/Chart.yaml",
  287. "charts/nginx/values.yaml",
  288. "charts/nginx/templates/deployment.yaml",
  289. }
  290. for _, f := range chartfiles {
  291. fq := filepath.Join(dir, f)
  292. if m, err := Load(dir, []string{fq}); err != nil || len(m) != 0 {
  293. t.Errorf("%q not ignored as a chart should be", f)
  294. }
  295. }
  296. }