github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/render/render_test.go (about) 1 package render 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/go-kit/kit/log" 13 "github.com/golang/mock/gomock" 14 "github.com/mitchellh/cli" 15 "github.com/replicatedhq/ship/pkg/api" 16 "github.com/replicatedhq/ship/pkg/lifecycle/daemon/daemontypes" 17 "github.com/replicatedhq/ship/pkg/lifecycle/render/planner" 18 _ "github.com/replicatedhq/ship/pkg/lifecycle/render/test-cases" 19 "github.com/replicatedhq/ship/pkg/state" 20 mockconfig "github.com/replicatedhq/ship/pkg/test-mocks/config" 21 mockdaemon "github.com/replicatedhq/ship/pkg/test-mocks/daemon" 22 mockplanner "github.com/replicatedhq/ship/pkg/test-mocks/planner" 23 "github.com/replicatedhq/ship/pkg/test-mocks/ui" 24 "github.com/replicatedhq/ship/pkg/testing/logger" 25 "github.com/spf13/afero" 26 "github.com/spf13/viper" 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 yaml "gopkg.in/yaml.v3" 30 ) 31 32 type testcase struct { 33 Name string 34 Metadata api.ReleaseMetadata 35 Spec api.Spec 36 ViperConfig map[string]interface{} `yaml:"viper_config"` 37 Responses map[string]string 38 Expect map[string]string 39 } 40 41 func TestRender(t *testing.T) { 42 ctx := context.Background() 43 44 tests := loadTestCases(t, filepath.Join("test-cases", "render-inline.yaml")) 45 46 for _, test := range tests { 47 t.Run(test.Name, func(t *testing.T) { 48 mc := gomock.NewController(t) 49 50 mockUI := ui.NewMockUi(mc) 51 p := mockplanner.NewMockPlanner(mc) 52 configResolver := mockconfig.NewMockResolver(mc) 53 mockFS := afero.Afero{Fs: afero.NewMemMapFs()} 54 mockDaemon := mockdaemon.NewMockDaemon(mc) 55 56 renderer := &headlessrenderer{ 57 Logger: log.NewNopLogger(), 58 Now: time.Now, 59 } 60 renderer.Fs = mockFS 61 renderer.UI = mockUI 62 renderer.ConfigResolver = configResolver 63 renderer.Planner = p 64 65 // this has to be the singleton state manager because ship will not always 66 // re-use renderer.StateManager 67 state, err := state.GetManager(renderer.Logger, mockFS, viper.New()) 68 assert.NoError(t, err) 69 70 renderer.StateManager = state 71 72 prog := mockDaemon.EXPECT().SetProgress(ProgressRead) 73 prog = mockDaemon.EXPECT().SetProgress(ProgressRender).After(prog) 74 prog = mockDaemon.EXPECT().SetStepName(ctx, daemontypes.StepNameConfirm).After(prog) 75 mockDaemon.EXPECT().ClearProgress().After(prog) 76 77 renderer.StatusReceiver = mockDaemon 78 79 release := &api.Release{Spec: test.Spec} 80 81 func() { 82 defer mc.Finish() 83 84 configResolver.EXPECT(). 85 ResolveConfig(ctx, release, gomock.Any()). 86 Return(test.ViperConfig, nil) 87 88 p.EXPECT(). 89 Build("installer", test.Spec.Assets.V1, test.Spec.Config.V1, gomock.Any(), test.ViperConfig). 90 Return(planner.Plan{}, []string{}, nil) 91 92 p.EXPECT(). 93 Execute(ctx, planner.Plan{}). 94 Return(nil) 95 96 err := renderer.Execute(ctx, release, &api.Render{}) 97 assert.NoError(t, err) 98 }() 99 }) 100 } 101 } 102 103 func TestBacksUpExisting(t *testing.T) { 104 tests := []struct { 105 name string 106 target string 107 existing []string 108 expect []string 109 }{ 110 { 111 name: "empty", 112 target: "/tmp/installer", 113 existing: []string{}, 114 expect: []string{}, 115 }, 116 { 117 name: "backs up file", 118 target: "/tmp/installer", 119 existing: []string{ 120 "/tmp/installer", 121 }, 122 expect: []string{ 123 "/tmp/installer.bak", 124 }, 125 }, 126 } 127 128 for _, test := range tests { 129 t.Run(test.name, func(t *testing.T) { 130 req := require.New(t) 131 mockFS := afero.Afero{Fs: afero.NewMemMapFs()} 132 r := headlessrenderer{ 133 Logger: &logger.TestLogger{T: t}, 134 Fs: mockFS, 135 Now: func() time.Time { 136 return time.Unix(12345, 0) 137 }, 138 UI: &cli.MockUi{}, 139 } 140 141 for _, filename := range test.existing { 142 err := mockFS.WriteFile(filename, []byte("not a directory but thats okay"), 0755) 143 req.NoError(err) 144 } 145 146 err := r.backupIfPresent(test.target) 147 req.NoError(err) 148 149 debugFs := &strings.Builder{} 150 err = r.Fs.Walk("/", func(path string, info os.FileInfo, err error) error { 151 debugFs.WriteString(path) 152 debugFs.WriteString("\n") 153 return nil 154 }) 155 req.NoError(err) 156 157 for _, filename := range test.expect { 158 exists, err := mockFS.Exists(filename) 159 req.NoError(err) 160 req.True(exists, "expected file %s to exist, fs had %s", filename, debugFs) 161 } 162 163 }) 164 } 165 } 166 167 func loadTestCases(t *testing.T, path string) []testcase { 168 tests := make([]testcase, 1) 169 contents, err := ioutil.ReadFile(path) 170 assert.NoError(t, err) 171 err = yaml.Unmarshal(contents, &tests) 172 assert.NoError(t, err) 173 return tests 174 }