github.com/bitrise-io/bitrise-step-update-gitops-repository@v0.0.0-20240426081835-1466be593380/pkg/gitops/templates_test.go (about)

     1  package gitops
     2  
     3  import (
     4  	"os"
     5  	"path"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  // Possible templates to render.
    13  const (
    14  	templateValuesYAML = `---
    15  api-service:
    16    image:
    17      name: "{{ .repository }}:{{ .tag }}"
    18  `
    19  	templateChartYAML = `---
    20  apiVersion: v2
    21  name: test
    22  description: A test service
    23  type: application
    24  version: 0.1.0
    25  appVersion: {{ .appVersion }}
    26  dependencies:
    27  - name: api-service
    28    version: "0.1.1"
    29    repository: "https://bitrise-io.github.io/k8s-recipes/"
    30  `
    31  	templateBrewFormulae = `
    32  class BitriseDenAgent < Formula
    33  	desc "CLI for Bitrise DEN agent"
    34  	homepage "https://github.com/bitrise-io/bitrise-den-agent"
    35  	url "https://github.com/bitrise-io/bitrise-den-agent.git",
    36  	  tag:      "{{ .brew_forumlae_tag }}",
    37  	  revision: "{{ .brew_forumlae_revision }}"
    38  	license ""
    39  end  
    40  `
    41  )
    42  
    43  // Possible outputs of rendered templates.
    44  const (
    45  	myRenderedValuesYAML = `---
    46  api-service:
    47    image:
    48      name: "myrepo:mytag"
    49  `
    50  	otherRenderedValuesYAML = `---
    51  api-service:
    52    image:
    53      name: "foo:bar"
    54  `
    55  	renderedChartYAML = `---
    56  apiVersion: v2
    57  name: test
    58  description: A test service
    59  type: application
    60  version: 0.1.0
    61  appVersion: 2.4.5
    62  dependencies:
    63  - name: api-service
    64    version: "0.1.1"
    65    repository: "https://bitrise-io.github.io/k8s-recipes/"
    66  `
    67  	renderedBrewFormulae = `
    68  class BitriseDenAgent < Formula
    69  	desc "CLI for Bitrise DEN agent"
    70  	homepage "https://github.com/bitrise-io/bitrise-den-agent"
    71  	url "https://github.com/bitrise-io/bitrise-den-agent.git",
    72  	  tag:      "v1.2.3",
    73  	  revision: "aaabbbcccdddeeefff"
    74  	license ""
    75  end  
    76  `
    77  )
    78  
    79  var renderAllFilesCases = map[string]struct {
    80  	templates map[string]string
    81  	values    map[string]string
    82  	folder    string
    83  	wantFiles map[string]string
    84  	wantErr   bool
    85  }{
    86  	"only values.yaml is rendered": {
    87  		templates: map[string]string{"values.yaml": templateValuesYAML},
    88  		values:    map[string]string{"repository": "myrepo", "tag": "mytag"},
    89  		folder:    "folder-with-values-yaml",
    90  		wantFiles: map[string]string{"values.yaml": myRenderedValuesYAML},
    91  	},
    92  	"values.yaml is rendered with other input": {
    93  		templates: map[string]string{"values.yaml": templateValuesYAML},
    94  		values:    map[string]string{"repository": "foo", "tag": "bar"},
    95  		folder:    "another-folder-with-values-yaml",
    96  		wantFiles: map[string]string{"values.yaml": otherRenderedValuesYAML},
    97  	},
    98  	"only Chart.yaml is rendered": {
    99  		templates: map[string]string{"Chart.yaml": templateChartYAML},
   100  		values:    map[string]string{"appVersion": "2.4.5"},
   101  		folder:    "folder-with-chart-yaml",
   102  		wantFiles: map[string]string{"Chart.yaml": renderedChartYAML},
   103  	},
   104  	"both Chart.yaml and values.yaml are rendered": {
   105  		templates: map[string]string{
   106  			"values.yaml": templateValuesYAML,
   107  			"Chart.yaml":  templateChartYAML,
   108  		},
   109  		values: map[string]string{
   110  			"repository": "myrepo",
   111  			"tag":        "mytag",
   112  			"appVersion": "2.4.5",
   113  		},
   114  		folder: "folder-with-multiple-files",
   115  		wantFiles: map[string]string{
   116  			"values.yaml": myRenderedValuesYAML,
   117  			"Chart.yaml":  renderedChartYAML,
   118  		},
   119  	},
   120  	"an unused template variable is present (it's ignored)": {
   121  		templates: map[string]string{"Chart.yaml": templateChartYAML},
   122  		values:    map[string]string{"appVersion": "2.4.5", "un": "used"},
   123  		folder:    "folder-with-unused-values",
   124  		wantFiles: map[string]string{"Chart.yaml": renderedChartYAML},
   125  	},
   126  	"a template variable is missing (error)": {
   127  		templates: map[string]string{"Chart.yaml": templateChartYAML},
   128  		values:    map[string]string{"appVersionTypo": "2.4.5"},
   129  		folder:    "wont-use-this-folder",
   130  		wantErr:   true,
   131  	},
   132  	"html tags are correctly rendered in brew formulae": {
   133  		templates: map[string]string{"formulae.rb": templateBrewFormulae},
   134  		values:    map[string]string{"brew_forumlae_tag": "v1.2.3", "brew_forumlae_revision": "aaabbbcccdddeeefff"},
   135  		folder:    "another-folder-with-values-yaml",
   136  		wantFiles: map[string]string{"formulae.rb": renderedBrewFormulae},
   137  	},
   138  }
   139  
   140  func TestRenderAllFiles(t *testing.T) {
   141  	for name, tc := range renderAllFilesCases {
   142  		t.Run(name, func(t *testing.T) {
   143  			// Create temporary directory for templates.
   144  			templatesDir, err := os.MkdirTemp("", "")
   145  			require.NoError(t, err, "new temp templates dir")
   146  			defer os.RemoveAll(templatesDir)
   147  
   148  			// Create a mock temporary directory for local clone of repository.
   149  			renderRepo, err := os.MkdirTemp("", "")
   150  			require.NoError(t, err, "new temp render repo")
   151  			defer os.RemoveAll(renderRepo)
   152  			// Create directory inside that for rendered files.
   153  			renderDir := path.Join(renderRepo, tc.folder)
   154  			require.NoError(t, os.Mkdir(renderDir, 0700), "new temp render dir")
   155  
   156  			// Copy desired templates to the previously created temp directory.
   157  			for fileName, content := range tc.templates {
   158  				filePath := path.Join(templatesDir, fileName)
   159  				err := os.WriteFile(filePath, []byte(content), 0600)
   160  				require.NoError(t, err, "write template %q", fileName)
   161  			}
   162  
   163  			// Run Templates.renderAllFiles.
   164  			tr := Templates{
   165  				SourceFolder: templatesDir,
   166  				Values:       tc.values,
   167  				DestinationRepo: &localRepositoryMock{
   168  					localPathFunc: func() string {
   169  						return renderRepo
   170  					},
   171  				},
   172  				DestinationFolder: tc.folder,
   173  			}
   174  
   175  			// Assert for error.
   176  			gotErr := tr.renderAllFiles()
   177  			if tc.wantErr {
   178  				require.Error(t, gotErr, "templatesRenderer.renderAllFiles")
   179  				return
   180  			}
   181  			require.NoError(t, gotErr, "templatesRenderer.renderAllFiles")
   182  
   183  			// Assert for name of rendered files.
   184  			var wantFileNames []string
   185  			for name := range tc.wantFiles {
   186  				wantFileNames = append(wantFileNames, name)
   187  			}
   188  
   189  			var gotFileNames []string
   190  			gotFileInfos, err := os.ReadDir(renderDir)
   191  			require.NoError(t, err, "read files of render dir")
   192  			for _, v := range gotFileInfos {
   193  				gotFileNames = append(gotFileNames, v.Name())
   194  			}
   195  
   196  			require.ElementsMatch(t, wantFileNames, gotFileNames, "file names")
   197  
   198  			// Assert for contents of rendered files.
   199  			for fileName, want := range tc.wantFiles {
   200  				filePath := path.Join(renderDir, fileName)
   201  				got, err := os.ReadFile(filePath)
   202  				require.NoError(t, err, "read contents of %q", filePath)
   203  				assert.EqualValues(t, want, string(got), "contents of %q", fileName)
   204  			}
   205  		})
   206  	}
   207  }