get.porter.sh/porter@v1.3.0/pkg/pkgmgmt/client/install_test.go (about) 1 package client 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "path" 11 "runtime" 12 "strings" 13 "testing" 14 15 "get.porter.sh/porter/pkg" 16 "get.porter.sh/porter/pkg/config" 17 "get.porter.sh/porter/pkg/pkgmgmt" 18 "get.porter.sh/porter/tests" 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 ) 22 23 func TestFileSystem_InstallFromUrl(t *testing.T) { 24 testcases := []struct { 25 name string 26 os string 27 arch string 28 responseCode map[string]int 29 wantError string 30 }{ 31 {name: "darwin/arm64 fallback to amd64", os: "darwin", arch: "arm64", responseCode: map[string]int{"arm64": 404}}, 32 {name: "darwin/arm64 binary exists", os: "darwin", arch: "arm64"}, 33 {name: "non-darwin arm64 no special handling", os: "myos", arch: "arm64", responseCode: map[string]int{"arm64": 404}, wantError: "404 Not Found"}, 34 } 35 36 for _, tc := range testcases { 37 t.Run(tc.name, func(t *testing.T) { 38 // serve out a fake package 39 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 40 for term, code := range tc.responseCode { 41 if strings.Contains(r.RequestURI, term) { 42 w.WriteHeader(code) 43 break 44 } 45 } 46 fmt.Fprintf(w, "#!/usr/bin/env bash\necho i am a random package\n") 47 })) 48 defer ts.Close() 49 50 c := config.NewTestConfig(t) 51 p := NewFileSystem(c.Config, "packages") 52 53 opts := pkgmgmt.InstallOptions{ 54 PackageType: "mixin", 55 Version: "latest", 56 URL: ts.URL, 57 } 58 err := opts.Validate([]string{"mypkg"}) 59 require.NoError(t, err, "Validate failed") 60 61 err = p.installFromURLFor(context.Background(), opts, tc.os, tc.arch) 62 if tc.wantError != "" { 63 tests.RequireErrorContains(t, err, tc.wantError) 64 } else { 65 require.NoError(t, err) 66 clientPath := "/home/myuser/.porter/packages/mypkg/mypkg" 67 if runtime.GOOS == "windows" { 68 clientPath += ".exe" 69 } 70 clientStats, err := p.FileSystem.Stat(clientPath) 71 require.NoError(t, err) 72 wantMode := pkg.FileModeExecutable 73 tests.AssertFilePermissionsEqual(t, clientPath, wantMode, clientStats.Mode()) 74 75 runtimePath := "/home/myuser/.porter/packages/mypkg/runtimes/mypkg-runtime" 76 runtimeStats, _ := p.FileSystem.Stat(runtimePath) 77 require.NoError(t, err) 78 tests.AssertFilePermissionsEqual(t, runtimePath, wantMode, runtimeStats.Mode()) 79 } 80 }) 81 } 82 } 83 84 func TestFileSystem_InstallFromFeedUrl(t *testing.T) { 85 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { 86 t.Skip("skipping because there is no release for helm for darwin/arm64") 87 } 88 89 var testURL = "" 90 feed, err := os.ReadFile("../feed/testdata/atom.xml") 91 require.NoError(t, err) 92 93 // serve out a fake feed and package 94 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 95 if strings.HasSuffix(r.RequestURI, "atom.xml") { 96 // swap out the urls in the test atom feed to match the test http server here so that porter downloads 97 // the package binaries from the fake server 98 testAtom := strings.Replace(string(feed), "https://cdn.porter.sh", testURL, -1) 99 fmt.Fprintln(w, testAtom) 100 } else { 101 fmt.Fprintf(w, "#!/usr/bin/env bash\necho i am helm\n") 102 } 103 })) 104 defer ts.Close() 105 testURL = ts.URL 106 107 c := config.NewTestConfig(t) 108 p := NewFileSystem(c.Config, "packages") 109 110 opts := pkgmgmt.InstallOptions{ 111 PackageType: "plugin", 112 Version: "v1.2.4", 113 FeedURL: ts.URL + "/atom.xml", 114 } 115 err = opts.Validate([]string{"helm"}) 116 require.NoError(t, err, "Validate failed") 117 118 err = p.Install(context.Background(), opts) 119 require.NoError(t, err) 120 121 clientExists, _ := p.FileSystem.Exists("/home/myuser/.porter/packages/helm/helm") 122 if runtime.GOOS == "windows" { 123 clientExists, _ = p.FileSystem.Exists("/home/myuser/.porter/packages/helm/helm.exe") 124 } 125 assert.True(t, clientExists) 126 runtimeExists, _ := p.FileSystem.Exists("/home/myuser/.porter/packages/helm/runtimes/helm-runtime") 127 assert.True(t, runtimeExists) 128 } 129 130 func TestFileSystem_Install_RollbackMissingRuntime(t *testing.T) { 131 // serve out a fake package 132 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 133 if strings.Contains(r.RequestURI, "linux-amd64") { 134 w.WriteHeader(400) 135 } else { 136 fmt.Fprintf(w, "#!/usr/bin/env bash\necho i am a client mypkg\n") 137 } 138 })) 139 defer ts.Close() 140 141 c := config.NewTestConfig(t) 142 p := NewFileSystem(c.Config, "packages") 143 144 parentDir, _ := p.GetPackagesDir() 145 pkgDir := path.Join(parentDir, "mypkg") 146 147 opts := pkgmgmt.InstallOptions{ 148 PackageType: "mixin", 149 Version: "latest", 150 URL: ts.URL, 151 } 152 err := opts.Validate([]string{"mypkg"}) 153 require.NoError(t, err, "Validate failed") 154 155 err = p.Install(context.Background(), opts) 156 require.Error(t, err) 157 assert.Contains(t, err.Error(), "bad status returned when downloading") 158 159 // Make sure the package directory was removed 160 dirExists, _ := p.FileSystem.DirExists(pkgDir) 161 assert.False(t, dirExists) 162 } 163 164 func TestFileSystem_Install_PackageInfoSavedWhenNoFileExists(t *testing.T) { 165 c := config.NewTestConfig(t) 166 p := NewFileSystem(c.Config, "packages") 167 168 packageURL := "https://cdn.porter.sh/mixins/helm" 169 opts := pkgmgmt.InstallOptions{ 170 PackageType: "plugin", 171 Version: "v1.2.4", 172 URL: packageURL, 173 } 174 name := "helm" 175 err := opts.Validate([]string{name}) 176 require.NoError(t, err, "Validate failed") 177 178 // ensure cache.json does not exist (yet) 179 cacheExists, _ := p.FileSystem.Exists("/home/myuser/.porter/packages/cache.json") 180 assert.False(t, cacheExists) 181 182 err = p.savePackageInfo(context.Background(), opts) 183 require.NoError(t, err) 184 185 // cache.json should have been created 186 cacheExists, _ = p.FileSystem.Exists("/home/myuser/.porter/packages/cache.json") 187 assert.True(t, cacheExists) 188 189 cacheContentsB, err := p.FileSystem.ReadFile("/home/myuser/.porter/packages/cache.json") 190 require.NoError(t, err) 191 192 //read cache.json 193 var allPackages packages 194 err = json.Unmarshal(cacheContentsB, &allPackages) 195 require.NoError(t, err) 196 197 //confirm that the required pkg is present 198 var pkgData PackageInfo 199 for _, pkg := range allPackages.Packages { 200 if pkg.Name == name { 201 pkgData = pkg 202 break 203 } 204 } 205 206 assert.Equal(t, name, pkgData.Name) 207 assert.Equal(t, packageURL, pkgData.URL) 208 }