github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/render/inline/render_test.go (about)

     1  package inline
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/replicatedhq/libyaml"
    12  	"github.com/spf13/afero"
    13  	"github.com/spf13/viper"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/replicatedhq/ship/pkg/api"
    17  	"github.com/replicatedhq/ship/pkg/lifecycle/render/root"
    18  	"github.com/replicatedhq/ship/pkg/templates"
    19  	"github.com/replicatedhq/ship/pkg/test-mocks/state"
    20  	"github.com/replicatedhq/ship/pkg/testing/logger"
    21  )
    22  
    23  func TestInlineRender(t *testing.T) {
    24  	type fileStruct struct {
    25  		contents string
    26  		path     string
    27  		mode     os.FileMode
    28  	}
    29  	tests := []struct {
    30  		name            string
    31  		asset           api.InlineAsset
    32  		meta            api.ReleaseMetadata
    33  		templateContext map[string]interface{}
    34  		configGroups    []libyaml.ConfigGroup
    35  		expect          fileStruct
    36  		expectErr       bool
    37  	}{
    38  		{
    39  			name: "happy path",
    40  			asset: api.InlineAsset{
    41  				Contents: "hello!",
    42  				AssetShared: api.AssetShared{
    43  					Dest: "foo.txt",
    44  				},
    45  			},
    46  			expect: fileStruct{
    47  				path:     "foo.txt",
    48  				contents: "hello!",
    49  				mode:     0644,
    50  			},
    51  
    52  			meta:            api.ReleaseMetadata{},
    53  			templateContext: map[string]interface{}{},
    54  			configGroups:    []libyaml.ConfigGroup{},
    55  		},
    56  		{
    57  			name: "templated dest path",
    58  			asset: api.InlineAsset{
    59  				Contents: "hello!",
    60  				AssetShared: api.AssetShared{
    61  					Dest: "{{repl if true}}foo.txt{{repl else}}notfoo.txt{{repl end}}",
    62  					Mode: os.ModePerm,
    63  				},
    64  			},
    65  			expect: fileStruct{
    66  				path:     "foo.txt",
    67  				contents: "hello!",
    68  				mode:     os.ModePerm,
    69  			},
    70  
    71  			meta:            api.ReleaseMetadata{},
    72  			templateContext: map[string]interface{}{},
    73  			configGroups:    []libyaml.ConfigGroup{},
    74  		},
    75  		{
    76  			name: "absolute dest path",
    77  			asset: api.InlineAsset{
    78  				Contents: "hello!",
    79  				AssetShared: api.AssetShared{
    80  					Dest: "/bin/runc",
    81  				},
    82  			},
    83  
    84  			meta:            api.ReleaseMetadata{},
    85  			templateContext: map[string]interface{}{},
    86  			configGroups:    []libyaml.ConfigGroup{},
    87  			expectErr:       true,
    88  		},
    89  		{
    90  			name: "parent dir dest path",
    91  			asset: api.InlineAsset{
    92  				Contents: "hello!",
    93  				AssetShared: api.AssetShared{
    94  					Dest: "../../../bin/runc",
    95  				},
    96  			},
    97  
    98  			meta:            api.ReleaseMetadata{},
    99  			templateContext: map[string]interface{}{},
   100  			configGroups:    []libyaml.ConfigGroup{},
   101  			expectErr:       true,
   102  		},
   103  		{
   104  			name: "odd filemode",
   105  			asset: api.InlineAsset{
   106  				Contents: "hello!",
   107  				AssetShared: api.AssetShared{
   108  					Dest: "foo.txt",
   109  					Mode: 0543,
   110  				},
   111  			},
   112  			expect: fileStruct{
   113  				path:     "foo.txt",
   114  				contents: "hello!",
   115  				mode:     0543,
   116  			},
   117  
   118  			meta:            api.ReleaseMetadata{},
   119  			templateContext: map[string]interface{}{},
   120  			configGroups:    []libyaml.ConfigGroup{},
   121  		},
   122  	}
   123  	for _, test := range tests {
   124  		t.Run(test.name+" aferoFS", func(t *testing.T) {
   125  			req := require.New(t)
   126  			testLogger := &logger.TestLogger{T: t}
   127  			v := viper.New()
   128  			bb := templates.NewBuilderBuilder(testLogger, v, &state.MockManager{})
   129  			rootFs := root.Fs{
   130  				Afero:    afero.Afero{Fs: afero.NewMemMapFs()},
   131  				RootPath: "",
   132  			}
   133  
   134  			renderer := &LocalRenderer{
   135  				Logger:         testLogger,
   136  				Viper:          v,
   137  				BuilderBuilder: bb,
   138  			}
   139  
   140  			err := renderer.Execute(
   141  				rootFs,
   142  				test.asset,
   143  				test.meta,
   144  				test.templateContext,
   145  				test.configGroups,
   146  			)(context.Background())
   147  			if !test.expectErr {
   148  				req.NoError(err)
   149  			} else {
   150  				req.Error(err)
   151  			}
   152  
   153  			if !test.expectErr {
   154  				contents, err := rootFs.ReadFile(test.expect.path)
   155  				req.NoError(err)
   156  				req.Equal(test.expect.contents, string(contents))
   157  				stat, err := rootFs.Stat(test.expect.path)
   158  				req.NoError(err)
   159  				req.Equal(test.expect.mode, stat.Mode())
   160  			}
   161  		})
   162  
   163  		t.Run(test.name+" real FS", func(t *testing.T) {
   164  			req := require.New(t)
   165  			testLogger := &logger.TestLogger{T: t}
   166  			v := viper.New()
   167  			bb := templates.NewBuilderBuilder(testLogger, v, &state.MockManager{})
   168  			tempdir, err := ioutil.TempDir("", "inline-render-test")
   169  			req.NoError(err)
   170  			defer os.RemoveAll(tempdir)
   171  			rootFs := root.Fs{
   172  				Afero:    afero.Afero{Fs: afero.NewBasePathFs(afero.NewOsFs(), tempdir)},
   173  				RootPath: "",
   174  			}
   175  
   176  			renderer := &LocalRenderer{
   177  				Logger:         testLogger,
   178  				Viper:          v,
   179  				BuilderBuilder: bb,
   180  			}
   181  
   182  			err = renderer.Execute(
   183  				rootFs,
   184  				test.asset,
   185  				test.meta,
   186  				test.templateContext,
   187  				test.configGroups,
   188  			)(context.Background())
   189  			if !test.expectErr {
   190  				req.NoError(err)
   191  			} else {
   192  				req.Error(err)
   193  			}
   194  
   195  			if !test.expectErr {
   196  				contents, err := rootFs.ReadFile(test.expect.path)
   197  				req.NoError(err)
   198  				req.Equal(test.expect.contents, string(contents))
   199  				stat, err := rootFs.Stat(test.expect.path)
   200  				req.NoError(err)
   201  				req.Equal(test.expect.mode, stat.Mode())
   202  			}
   203  		})
   204  	}
   205  }
   206  
   207  func TestAfero(t *testing.T) {
   208  	modes := []os.FileMode{
   209  		os.ModePerm,
   210  		0666,
   211  		0555,
   212  		0444,
   213  		0333,
   214  		0222,
   215  		0111,
   216  		0000,
   217  		0644,
   218  		0600,
   219  		0700,
   220  		0733,
   221  		0777,
   222  		0755,
   223  	}
   224  	for _, mode := range modes {
   225  		t.Run(fmt.Sprint(mode)+" afero FS", func(t *testing.T) {
   226  			req := require.New(t)
   227  			aferoFS := afero.Afero{Fs: afero.NewMemMapFs()}
   228  
   229  			err := aferoFS.WriteFile("test.txt", []byte("Hello, World!"), mode)
   230  			req.NoError(err)
   231  			err = aferoFS.Chmod("test.txt", mode)
   232  			req.NoError(err)
   233  
   234  			stat, err := aferoFS.Stat("test.txt")
   235  			req.NoError(err)
   236  
   237  			req.Equal(fmt.Sprint(mode), fmt.Sprint(stat.Mode()))
   238  		})
   239  
   240  		t.Run(fmt.Sprint(mode)+" real FS", func(t *testing.T) {
   241  			req := require.New(t)
   242  			tempdir, err := ioutil.TempDir("", "afero-test")
   243  			req.NoError(err)
   244  			defer os.RemoveAll(tempdir)
   245  			realFS := afero.Afero{Fs: afero.NewBasePathFs(afero.NewOsFs(), tempdir)}
   246  
   247  			err = realFS.WriteFile("test.txt", []byte("Hello, World!"), mode)
   248  			req.NoError(err)
   249  			err = realFS.Chmod("test.txt", mode)
   250  			req.NoError(err)
   251  
   252  			stat, err := realFS.Stat("test.txt")
   253  			req.NoError(err)
   254  
   255  			req.Equal(fmt.Sprint(mode), fmt.Sprint(stat.Mode()))
   256  		})
   257  
   258  		t.Run(fmt.Sprint(mode)+" manual FS", func(t *testing.T) {
   259  			req := require.New(t)
   260  			tempdir, err := ioutil.TempDir("", "afero-test")
   261  			req.NoError(err)
   262  			defer os.RemoveAll(tempdir)
   263  
   264  			err = ioutil.WriteFile(filepath.Join(tempdir, "test.txt"), []byte("Hello, World!"), mode)
   265  			req.NoError(err)
   266  			err = os.Chmod(filepath.Join(tempdir, "test.txt"), mode)
   267  			req.NoError(err)
   268  			stat, err := os.Stat(filepath.Join(tempdir, "test.txt"))
   269  			req.NoError(err)
   270  
   271  			req.Equal(fmt.Sprint(mode), fmt.Sprint(stat.Mode()))
   272  		})
   273  	}
   274  }