diff --git a/go.mod b/go.mod index f52bcb28b..02e367f71 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/oracle/oci-go-sdk v7.1.0+incompatible github.com/pquerna/otp v1.2.0 github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/tmccombs/hcl2json v0.3.3 github.com/urfave/cli v1.22.2 github.com/zclconf/go-cty v1.9.1 @@ -48,6 +48,8 @@ require ( require ( cloud.google.com/go/cloudbuild v1.9.0 + github.com/gonvenience/ytbx v1.4.4 + github.com/homeport/dyff v1.6.0 github.com/slack-go/slack v0.10.3 gotest.tools/v3 v3.0.3 ) @@ -63,6 +65,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect @@ -83,6 +86,11 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/gonvenience/bunt v1.3.5 // indirect + github.com/gonvenience/neat v1.3.12 // indirect + github.com/gonvenience/term v1.0.2 // indirect + github.com/gonvenience/text v1.0.7 // indirect + github.com/gonvenience/wrap v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -97,9 +105,14 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.15.11 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/hashstructure v1.1.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -110,10 +123,13 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/texttheater/golang-levenshtein v1.0.1 // indirect github.com/ulikunitz/xz v0.5.10 // indirect + github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/sync v0.1.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/go.sum b/go.sum index 9cf03e367..124debf5f 100644 --- a/go.sum +++ b/go.sum @@ -226,6 +226,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -482,6 +484,8 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -577,6 +581,18 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gonvenience/bunt v1.3.5 h1:wSQquifvwEWtzn27k1ngLfeLaStyt0k1b/K6TrlCNAs= +github.com/gonvenience/bunt v1.3.5/go.mod h1:7ApqkVBEWvX04oJ28Q2WeI/BvJM6VtukaJAU/q/pTs8= +github.com/gonvenience/neat v1.3.12 h1:xwIyRbJcG9LgcDYys+HHLH9DqqHeQsUpS5CfBUeskbs= +github.com/gonvenience/neat v1.3.12/go.mod h1:8OljAIgPelN0uPPO94VBqxK+Kz98d6ZFwHDg5o/PfkE= +github.com/gonvenience/term v1.0.2 h1:qKa2RydbWIrabGjR/fegJwpW5m+JvUwFL8mLhHzDXn0= +github.com/gonvenience/term v1.0.2/go.mod h1:wThTR+3MzWtWn7XGVW6qQ65uaVf8GHED98KmwpuEQeo= +github.com/gonvenience/text v1.0.7 h1:YmIqmgTwxnACYCG59DykgMbomwteYyNhAmEUEJtPl14= +github.com/gonvenience/text v1.0.7/go.mod h1:OAjH+mohRszffLY6OjgQcUXiSkbrIavooFpfIt1ZwAs= +github.com/gonvenience/wrap v1.1.2 h1:xPKxNwL1HCguwyM+HlP/1CIuc9LRd7k8RodLwe9YTZA= +github.com/gonvenience/wrap v1.1.2/go.mod h1:GiryBSXoI3BAAhbWD1cZVj7RZmtiu0ERi/6R6eJfslI= +github.com/gonvenience/ytbx v1.4.4 h1:jQopwyaLsVGuwdxSiN4WkXjsEaFNPJ3V4lUj7eyEpzo= +github.com/gonvenience/ytbx v1.4.4/go.mod h1:w37+MKCPcCMY/jpPNmEklD4xKqrOAVBO6kIWW2+uI6M= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -623,8 +639,9 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= +github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -654,6 +671,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -705,6 +724,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY= github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= +github.com/homeport/dyff v1.6.0 h1:AN+ikld0Fy+qx34YE7655b/bpWuxS6cL9k852pE2GUc= +github.com/homeport/dyff v1.6.0/go.mod h1:FlAOFYzeKvxmU5nTrnG+qrlJVWpsFew7pt8L99p5q8k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -765,6 +786,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -774,12 +797,16 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 h1:BXxTozrOU8zgC5dkpn3J6NTRdoP+hjok/e+ACr4Hibk= +github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3/go.mod h1:x1uk6vxTiVuNt6S5R2UYgdhpj3oKojXvOXauHZ7dEnI= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= @@ -798,6 +825,8 @@ github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HK github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= @@ -805,6 +834,8 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0= +github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -835,6 +866,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -843,17 +876,18 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= -github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c= +github.com/onsi/gomega v1.28.0/go.mod h1:A1H2JE76sI14WIP57LMKj7FVfCHx3g3BcZVjJG8bjX8= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -941,6 +975,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -995,13 +1031,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U= +github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmccombs/hcl2json v0.3.3 h1:+DLNYqpWE0CsOQiEZu+OZm5ZBImake3wtITYxQ8uLFQ= @@ -1014,6 +1052,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= @@ -1234,8 +1274,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1342,6 +1382,7 @@ golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1429,8 +1470,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1688,6 +1729,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/modules/helm/options.go b/modules/helm/options.go index bafdedea4..da210ef1b 100644 --- a/modules/helm/options.go +++ b/modules/helm/options.go @@ -18,4 +18,5 @@ type Options struct { Logger *logger.Logger // Set a non-default logger that should be used. See the logger package for more info. Use logger.Discard to not print the output while executing the command. ExtraArgs map[string][]string // Extra arguments to pass to the helm install/upgrade/rollback/delete and helm repo add commands. The key signals the command (e.g., install) while the values are the extra arguments to pass through. BuildDependencies bool // If true, helm dependencies will be built before rendering template, installing or upgrade the chart. + SnapshotPath string // The path to the snapshot directory when using snapshot based testing. Empty string means use default ($PWD/__snapshot__). } diff --git a/modules/helm/template.go b/modules/helm/template.go index a9070e12d..0cebe0bb1 100644 --- a/modules/helm/template.go +++ b/modules/helm/template.go @@ -11,6 +11,11 @@ import ( "github.com/gruntwork-io/terratest/modules/files" "github.com/gruntwork-io/terratest/modules/testing" + + "os" + + "github.com/gonvenience/ytbx" + "github.com/homeport/dyff/pkg/dyff" ) // RenderTemplate runs `helm template` to render the template given the provided options and returns stdout/stderr from @@ -134,3 +139,123 @@ func UnmarshalK8SYamlE(t testing.TestingT, yamlData string, destinationObj inter } return nil } + +// UpdateSnapshot creates or updates the k8s manifest snapshot of a chart (e.g bitnami/nginx). +// It is one of the two functions needed to implement snapshot based testing for helm. +// see https://github.com/gruntwork-io/terratest/issues/1377 +// A snapshot is used to compare the current manifests of a chart with the previous manifests. +// A global diff is run against the two snapshosts and the number of differences is returned. +func UpdateSnapshot(t testing.TestingT, options *Options, yamlData string, releaseName string) { + require.NoError(t, UpdateSnapshotE(t, options, yamlData, releaseName)) +} + +// UpdateSnapshotE creates or updates the k8s manifest snapshot of a chart (e.g bitnami/nginx). +// It is one of the two functions needed to implement snapshot based testing for helm. +// see https://github.com/gruntwork-io/terratest/issues/1377 +// A snapshot is used to compare the current manifests of a chart with the previous manifests. +// A global diff is run against the two snapshosts and the number of differences is returned. +// It will failed the test if there is an error while writing the manifests' snapshot in the file system +func UpdateSnapshotE(t testing.TestingT, options *Options, yamlData string, releaseName string) error { + + var snapshotDir = "__snapshot__" + if options.SnapshotPath != "" { + snapshotDir = options.SnapshotPath + } + // Create a directory if not exists + if !files.FileExists(snapshotDir) { + if err := os.Mkdir(snapshotDir, 0755); err != nil { + return errors.WithStackTrace(err) + } + } + + filename := filepath.Join(snapshotDir, releaseName+".yaml") + // Open a file in write mode + file, err := os.Create(filename) + if err != nil { + return errors.WithStackTrace(err) + } + defer file.Close() + + // Write the k8s manifest into the file + if _, err = file.WriteString(yamlData); err != nil { + return errors.WithStackTrace(err) + } + + if options.Logger != nil { + options.Logger.Logf(t, "helm chart manifest written into file: %s", filename) + } + return nil +} + +// DiffAgainstSnapshot compare the current manifests of a chart (e.g bitnami/nginx) +// with the previous manifests stored in the snapshot. +// see https://github.com/gruntwork-io/terratest/issues/1377 +// It returns the number of difference between the two manifests or -1 in case of error +// It will fail the test if there is an error while reading or writing the two manifests in the file system +func DiffAgainstSnapshot(t testing.TestingT, options *Options, yamlData string, releaseName string) int { + numberOfDiffs, err := DiffAgainstSnapshotE(t, options, yamlData, releaseName) + require.NoError(t, err) + return numberOfDiffs +} + +// DiffAgainstSnapshotE compare the current manifests of a chart (e.g bitnami/nginx) +// with the previous manifests stored in the snapshot. +// see https://github.com/gruntwork-io/terratest/issues/1377 +// It returns the number of difference between the manifests or -1 in case of error +func DiffAgainstSnapshotE(t testing.TestingT, options *Options, yamlData string, releaseName string) (int, error) { + + var snapshotDir = "__snapshot__" + if options.SnapshotPath != "" { + snapshotDir = options.SnapshotPath + } + + // load the yaml snapshot file + snapshot := filepath.Join(snapshotDir, releaseName+".yaml") + from, err := ytbx.LoadFile(snapshot) + if err != nil { + return -1, errors.WithStackTrace(err) + } + + // write the current manifest into a file as `dyff` does not support string input + currentManifests := releaseName + ".yaml" + file, err := os.Create(currentManifests) + if err != nil { + return -1, errors.WithStackTrace(err) + } + + if _, err = file.WriteString(yamlData); err != nil { + return -1, errors.WithStackTrace(err) + } + defer file.Close() + defer os.Remove(currentManifests) + + to, err := ytbx.LoadFile(currentManifests) + if err != nil { + return -1, errors.WithStackTrace(err) + } + + // compare the two manifests using `dyff` + compOpt := dyff.KubernetesEntityDetection(false) + + // create a report + report, err := dyff.CompareInputFiles(from, to, compOpt) + if err != nil { + return -1, errors.WithStackTrace(err) + } + + // write any difference to stdout + reportWriter := &dyff.HumanReport{ + Report: report, + DoNotInspectCerts: false, + NoTableStyle: false, + OmitHeader: false, + UseGoPatchPaths: false, + } + + err = reportWriter.WriteReport(os.Stdout) + if err != nil { + return -1, errors.WithStackTrace(err) + } + // return the number of diffs to use in assertion while testing: 0 = no differences + return len(reportWriter.Diffs), nil +} diff --git a/modules/helm/template_test.go b/modules/helm/template_test.go index 1c212099b..8de17575d 100644 --- a/modules/helm/template_test.go +++ b/modules/helm/template_test.go @@ -17,6 +17,7 @@ import ( appsv1 "k8s.io/api/apps/v1" "github.com/gruntwork-io/terratest/modules/k8s" + "github.com/gruntwork-io/terratest/modules/logger" "github.com/gruntwork-io/terratest/modules/random" ) @@ -25,7 +26,7 @@ func TestRemoteChartRender(t *testing.T) { const ( remoteChartSource = "https://charts.bitnami.com/bitnami" remoteChartName = "nginx" - remoteChartVersion = "13.2.23" + remoteChartVersion = "13.2.24" ) t.Parallel() @@ -45,6 +46,7 @@ func TestRemoteChartRender(t *testing.T) { "image.tag": remoteChartVersion, }, KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, } // Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since @@ -65,3 +67,81 @@ func TestRemoteChartRender(t *testing.T) { require.Equal(t, len(deploymentContainers), 1) require.Equal(t, deploymentContainers[0].Image, expectedContainerImage) } + +// Test that we can dump all the manifest locally a remote chart (e.g bitnami/nginx) +// so that I can use them later to compare between two versions of the same chart for example +func TestRemoteChartRenderDump(t *testing.T) { + const ( + remoteChartSource = "https://charts.bitnami.com/bitnami" + remoteChartName = "nginx" + remoteChartVersion = "13.2.20" + // need to set a fix name for the namespace so it is not flag as a difference + namespaceName = "dump-ns" + ) + + releaseName := remoteChartName + + options := &Options{ + SetValues: map[string]string{ + "image.repository": remoteChartName, + "image.registry": "", + "image.tag": remoteChartVersion, + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + output := RenderRemoteTemplate(t, options, remoteChartSource, releaseName, []string{}) + + // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will + // ensure the Deployment resource is rendered correctly. + var deployment appsv1.Deployment + UnmarshalK8SYaml(t, output, &deployment) + + // Verify the namespace matches the expected supplied namespace. + require.Equal(t, namespaceName, deployment.Namespace) + + // write chart manifest to a local filesystem directory + options = &Options{ + Logger: logger.Default, + SnapshotPath: "__chart_manifests_snapshot__", + } + UpdateSnapshot(t, options, output, releaseName) +} + +// Test that we can diff all the manifest to a local snapshot using a remote chart (e.g bitnami/nginx) +func TestRemoteChartRenderDiff(t *testing.T) { + const ( + remoteChartSource = "https://charts.bitnami.com/bitnami" + remoteChartName = "nginx" + remoteChartVersion = "13.2.24" + // need to set a fix name for the namespace so it is not flag as a difference + namespaceName = "dump-ns" + ) + + releaseName := remoteChartName + options := &Options{ + SetValues: map[string]string{ + "image.repository": remoteChartName, + "image.registry": "", + "image.tag": remoteChartVersion, + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + SnapshotPath: "__chart_manifests_snapshot__", + } + + // Run RenderTemplate to render the template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + output := RenderRemoteTemplate(t, options, remoteChartSource, releaseName, []string{}) + + // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will + // ensure the Deployment resource is rendered correctly. + var deployment appsv1.Deployment + UnmarshalK8SYaml(t, output, &deployment) + + // run the diff and assert there is only one difference: the image name + require.Equal(t, 1, DiffAgainstSnapshot(t, options, output, releaseName)) +} diff --git a/test/fixtures/helm/keda-values.yaml b/test/fixtures/helm/keda-values.yaml new file mode 100644 index 000000000..6dc15cf75 --- /dev/null +++ b/test/fixtures/helm/keda-values.yaml @@ -0,0 +1,30 @@ +metricsServer: + replicaCount: 3 +operator: + name: keda-operator + replicaCount: 3 +podAnnotations: + keda: + sidecar.istio.io/inject: "false" + metricsAdapter: + sidecar.istio.io/inject: "false" +podDisruptionBudget: + metricServer: + minAvailable: 1 + operator: + minAvailable: 1 +resources: + metricServer: + limits: + cpu: 100m + memory: 1234Mi + requests: + cpu: 50m + memory: 128Mi + operator: + limits: + cpu: 100m + memory: 1111Mi + requests: + cpu: 50m + memory: 888Mi diff --git a/test/helm_keda_remote_example_template_snapshot_test.go b/test/helm_keda_remote_example_template_snapshot_test.go new file mode 100644 index 000000000..3efddc837 --- /dev/null +++ b/test/helm_keda_remote_example_template_snapshot_test.go @@ -0,0 +1,177 @@ +//go:build kubeall || helm +// +build kubeall helm + +// **NOTE**: we have build tags to differentiate kubernetes tests from non-kubernetes tests, and further differentiate helm +// tests. This is done because minikube is heavy and can interfere with docker related tests in terratest. Similarly, helm +// can overload the minikube system and thus interfere with the other kubernetes tests. Specifically, many of the tests +// start to fail with `connection refused` errors from `minikube`. To avoid overloading the system, we run the kubernetes +// tests and helm tests separately from the others. This may not be necessary if you have a sufficiently powerful machine. +// We recommend at least 4 cores and 16GB of RAM if you want to run all the tests together. + +package test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + + "github.com/gruntwork-io/terratest/modules/helm" + "github.com/gruntwork-io/terratest/modules/k8s" + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/random" +) + +// This file contains an example of how to use terratest to test *remote* helm chart template logic by rendering the templates +// using `helm template`, and then reading in the rendered templates. +// - TestHelmKedaRemoteExampleTemplateRenderedDeployment: An example of how to read in the rendered object and check the +// computed values. + +// An example of how to verify the rendered template object of a Helm Chart given various inputs. +func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDump(t *testing.T) { + + // chart name + releaseName := "keda" + + // Set up the namespace; confirm that the template renders the expected value for the namespace. + namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) + logger.Logf(t, "Namespace: %s\n", namespaceName) + + // Setup the args. For this test, we will set the following input values: + options := &helm.Options{ + SetValues: map[string]string{ + "metricsServer.replicaCount": "999", + "resources.metricServer.limits.memory": "1234Mi", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + // Additionally, we path a the templateFile for which we are setting test values to + // demonstrate how to select individual templates to render. + output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{"templates/metrics-server/deployment.yaml"}) + + // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will + // ensure the Deployment resource is rendered correctly. + var deployment appsv1.Deployment + helm.UnmarshalK8SYaml(t, output, &deployment) + + // Verify the namespace matches the expected supplied namespace. + require.Equal(t, namespaceName, deployment.Namespace) + + // Finally, we verify the deployment pod template spec is set to the expected container image value + var expectedMetricsServerReplica int32 + expectedMetricsServerReplica = 999 + deploymentMetricsServerReplica := *deployment.Spec.Replicas + require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica) + + // write chart manifest to a local filesystem directory + helm.UpdateSnapshot(t, options, output, releaseName) +} + +// An example of how to verify the rendered template object of a Helm Chart given various inputs. +func TestHelmKedaRemoteExampleTemplateRenderedDeploymentDiff(t *testing.T) { + + // chart name + releaseName := "keda" + + // Set up the namespace; confirm that the template renders the expected value for the namespace. + namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) + logger.Logf(t, "Namespace: %s\n", namespaceName) + + // Setup the args. For this test, we will set the following input values: + options := &helm.Options{ + SetValues: map[string]string{ + "metricsServer.replicaCount": "666", + "resources.metricServer.limits.memory": "4321Mi", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + // Additionally, we path a the templateFile for which we are setting test values to + // demonstrate how to select individual templates to render. + output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{"templates/metrics-server/deployment.yaml"}) + + // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will + // ensure the Deployment resource is rendered correctly. + var deployment appsv1.Deployment + helm.UnmarshalK8SYaml(t, output, &deployment) + + // Verify the namespace matches the expected supplied namespace. + require.Equal(t, namespaceName, deployment.Namespace) + + // Finally, we verify the deployment pod template spec is set to the expected container image value + var expectedMetricsServerReplica int32 + expectedMetricsServerReplica = 666 + deploymentMetricsServerReplica := *deployment.Spec.Replicas + require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica) + + // run the diff and assert the number of diffs + require.Equal(t, 4, helm.DiffAgainstSnapshot(t, options, output, releaseName)) +} + +// An example of how to store a snapshot of the current manaifest for future comparison +func TestHelmKedaRemoteExampleTemplateRenderedPackageDump(t *testing.T) { + + // chart name + releaseName := "keda" + + // Set up the namespace; confirm that the template renders the expected value for the namespace. + namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) + logger.Logf(t, "Namespace: %s\n", namespaceName) + + // Setup the args. For this test, we will set the following input values: + options := &helm.Options{ + SetValues: map[string]string{ + "metricsServer.replicaCount": "999", + "resources.metricServer.limits.memory": "1234Mi", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + // Additionally, we path a the templateFile for which we are setting test values to + // demonstrate how to select individual templates to render. + output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{}) + + // write chart manifest to a local filesystem directory + helm.UpdateSnapshot(t, options, output, releaseName) +} + +// An example of how to verify the current helm k8s manifest against a previous snapshot +func TestHelmKedaRemoteExampleTemplateRenderedPackageDiff(t *testing.T) { + + // chart name + releaseName := "keda" + + // Set up the namespace; confirm that the template renders the expected value for the namespace. + namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) + logger.Logf(t, "Namespace: %s\n", namespaceName) + + // Setup the args. For this test, we will set the following input values: + options := &helm.Options{ + SetValues: map[string]string{ + "metricsServer.replicaCount": "666", + "resources.metricServer.limits.memory": "4321Mi", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + // Additionally, we path a the templateFile for which we are setting test values to + // demonstrate how to select individual templates to render. + output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{}) + + // run the diff and assert the number of diffs matches the number of diffs in the snapshot + require.Equal(t, 18, helm.DiffAgainstSnapshot(t, options, output, releaseName)) +} diff --git a/test/helm_keda_remote_example_template_test.go b/test/helm_keda_remote_example_template_test.go index dbf6bbc59..1f66dda40 100644 --- a/test/helm_keda_remote_example_template_test.go +++ b/test/helm_keda_remote_example_template_test.go @@ -46,6 +46,7 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeployment(t *testing.T) { "resources.metricServer.limits.memory": "1234Mi", }, KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, } // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since @@ -67,4 +68,51 @@ func TestHelmKedaRemoteExampleTemplateRenderedDeployment(t *testing.T) { expectedMetricsServerReplica = 999 deploymentMetricsServerReplica := *deployment.Spec.Replicas require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica) + expectedContainerRLM := "1234Mi" + deploymentContainers := deployment.Spec.Template.Spec.Containers + require.Equal(t, len(deploymentContainers), 1) + currentContainerRLM := deploymentContainers[0].Resources.Limits.Memory().String() + require.Equal(t, currentContainerRLM, expectedContainerRLM) +} + +// An example of how to verify the rendered template object of a Helm Chart given input from a `values.yaml` file. +func TestHelmKedaRemoteExampleTemplateRenderedValuesFileFixtureDeployment(t *testing.T) { + t.Parallel() + + // chart name + releaseName := "keda" + + // Set up the namespace; confirm that the template renders the expected value for the namespace. + namespaceName := "medieval-" + strings.ToLower(random.UniqueId()) + logger.Logf(t, "Namespace: %s\n", namespaceName) + options := &helm.Options{ + ValuesFiles: []string{"./fixtures/helm/keda-values.yaml"}, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + Logger: logger.Discard, + } + + // Run RenderTemplate to render the *remote* template and capture the output. Note that we use the version without `E`, since + // we want to assert that the template renders without any errors. + // Additionally, we path a the templateFile for which we are setting test values to + // demonstrate how to select individual templates to render. + output := helm.RenderRemoteTemplate(t, options, "https://kedacore.github.io/charts", releaseName, []string{"templates/metrics-server/deployment.yaml"}) + + // Now we use kubernetes/client-go library to render the template output into the Deployment struct. This will + // ensure the Deployment resource is rendered correctly. + var deployment appsv1.Deployment + helm.UnmarshalK8SYaml(t, output, &deployment) + + // Verify the namespace matches the expected supplied namespace. + require.Equal(t, namespaceName, deployment.Namespace) + + // Finally, we verify the deployment pod template spec is set to the expected value + var expectedMetricsServerReplica int32 + expectedMetricsServerReplica = 3 + deploymentMetricsServerReplica := *deployment.Spec.Replicas + require.Equal(t, expectedMetricsServerReplica, deploymentMetricsServerReplica) + expectedContainerRLM := "1234Mi" + deploymentContainers := deployment.Spec.Template.Spec.Containers + require.Equal(t, len(deploymentContainers), 1) + currentContainerRLM := deploymentContainers[0].Resources.Limits.Memory().String() + require.Equal(t, currentContainerRLM, expectedContainerRLM) }