github.com/latiif/helm@v2.15.0+incompatible/pkg/plugin/installer/http_installer_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package installer // import "k8s.io/helm/pkg/plugin/installer" 17 18 import ( 19 "archive/tar" 20 "bytes" 21 "compress/gzip" 22 "encoding/base64" 23 "fmt" 24 "io/ioutil" 25 "k8s.io/helm/pkg/helm/helmpath" 26 "os" 27 "path/filepath" 28 "syscall" 29 "testing" 30 ) 31 32 var _ Installer = new(HTTPInstaller) 33 34 // Fake http client 35 type TestHTTPGetter struct { 36 MockResponse *bytes.Buffer 37 MockError error 38 } 39 40 func (t *TestHTTPGetter) Get(href string) (*bytes.Buffer, error) { return t.MockResponse, t.MockError } 41 42 // Fake plugin tarball data 43 var fakePluginB64 = "H4sIAKRj51kAA+3UX0vCUBgGcC9jn+Iwuk3Peza3GeyiUlJQkcogCOzgli7dJm4TvYk+a5+k479UqquUCJ/fLs549sLO2TnvWnJa9aXnjwujYdYLovxMhsPcfnHOLdNkOXthM/IVQQYjg2yyLLJ4kXGhLp5j0z3P41tZksqxmspL3B/O+j/XtZu1y8rdYzkOZRCxduKPk53ny6Wwz/GfIIf1As8lxzGJSmoHNLJZphKHG4YpTCE0wVk3DULfpSJ3DMMqkj3P5JfMYLdX1Vr9Ie/5E5cstcdC8K04iGLX5HaJuKpWL17F0TCIBi5pf/0pjtLhun5j3f9v6r7wfnI/H0eNp9d1/5P6Gez0vzo7wsoxfrAZbTny/o9k6J8z/VkO/LPlWdC1iVpbEEcq5nmeJ13LEtmbV0k2r2PrOs9PuuNglC5rL1Y5S/syXRQmutaNw1BGnnp8Wq3UG51WvX1da3bKtZtCN/R09DwAAAAAAAAAAAAAAAAAAADAb30AoMczDwAoAAA=" 44 45 func TestStripName(t *testing.T) { 46 if stripPluginName("fake-plugin-0.0.1.tar.gz") != "fake-plugin" { 47 t.Errorf("name does not match expected value") 48 } 49 if stripPluginName("fake-plugin-0.0.1.tgz") != "fake-plugin" { 50 t.Errorf("name does not match expected value") 51 } 52 if stripPluginName("fake-plugin.tgz") != "fake-plugin" { 53 t.Errorf("name does not match expected value") 54 } 55 if stripPluginName("fake-plugin.tar.gz") != "fake-plugin" { 56 t.Errorf("name does not match expected value") 57 } 58 } 59 60 func TestHTTPInstaller(t *testing.T) { 61 source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" 62 hh, err := ioutil.TempDir("", "helm-home-") 63 if err != nil { 64 t.Fatal(err) 65 } 66 defer os.RemoveAll(hh) 67 68 home := helmpath.Home(hh) 69 if err := os.MkdirAll(home.Plugins(), 0755); err != nil { 70 t.Fatalf("Could not create %s: %s", home.Plugins(), err) 71 } 72 73 i, err := NewForSource(source, "0.0.1", home) 74 if err != nil { 75 t.Errorf("unexpected error: %s", err) 76 } 77 78 // ensure a HTTPInstaller was returned 79 httpInstaller, ok := i.(*HTTPInstaller) 80 if !ok { 81 t.Error("expected a HTTPInstaller") 82 } 83 84 // inject fake http client responding with minimal plugin tarball 85 mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) 86 if err != nil { 87 t.Fatalf("Could not decode fake tgz plugin: %s", err) 88 } 89 90 httpInstaller.getter = &TestHTTPGetter{ 91 MockResponse: bytes.NewBuffer(mockTgz), 92 } 93 94 // install the plugin 95 if err := Install(i); err != nil { 96 t.Error(err) 97 } 98 if i.Path() != home.Path("plugins", "fake-plugin") { 99 t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) 100 } 101 102 // Install again to test plugin exists error 103 if err := Install(i); err == nil { 104 t.Error("expected error for plugin exists, got none") 105 } else if err.Error() != "plugin already exists" { 106 t.Errorf("expected error for plugin exists, got (%v)", err) 107 } 108 109 } 110 111 func TestHTTPInstallerNonExistentVersion(t *testing.T) { 112 source := "https://repo.localdomain/plugins/fake-plugin-0.0.2.tar.gz" 113 hh, err := ioutil.TempDir("", "helm-home-") 114 if err != nil { 115 t.Fatal(err) 116 } 117 defer os.RemoveAll(hh) 118 119 home := helmpath.Home(hh) 120 if err := os.MkdirAll(home.Plugins(), 0755); err != nil { 121 t.Fatalf("Could not create %s: %s", home.Plugins(), err) 122 } 123 124 i, err := NewForSource(source, "0.0.2", home) 125 if err != nil { 126 t.Errorf("unexpected error: %s", err) 127 } 128 129 // ensure a HTTPInstaller was returned 130 httpInstaller, ok := i.(*HTTPInstaller) 131 if !ok { 132 t.Error("expected a HTTPInstaller") 133 } 134 135 // inject fake http client responding with error 136 httpInstaller.getter = &TestHTTPGetter{ 137 MockError: fmt.Errorf("failed to download plugin for some reason"), 138 } 139 140 // attempt to install the plugin 141 if err := Install(i); err == nil { 142 t.Error("expected error from http client") 143 } 144 145 } 146 147 func TestHTTPInstallerUpdate(t *testing.T) { 148 source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz" 149 hh, err := ioutil.TempDir("", "helm-home-") 150 if err != nil { 151 t.Fatal(err) 152 } 153 defer os.RemoveAll(hh) 154 155 home := helmpath.Home(hh) 156 if err := os.MkdirAll(home.Plugins(), 0755); err != nil { 157 t.Fatalf("Could not create %s: %s", home.Plugins(), err) 158 } 159 160 i, err := NewForSource(source, "0.0.1", home) 161 if err != nil { 162 t.Errorf("unexpected error: %s", err) 163 } 164 165 // ensure a HTTPInstaller was returned 166 httpInstaller, ok := i.(*HTTPInstaller) 167 if !ok { 168 t.Error("expected a HTTPInstaller") 169 } 170 171 // inject fake http client responding with minimal plugin tarball 172 mockTgz, err := base64.StdEncoding.DecodeString(fakePluginB64) 173 if err != nil { 174 t.Fatalf("Could not decode fake tgz plugin: %s", err) 175 } 176 177 httpInstaller.getter = &TestHTTPGetter{ 178 MockResponse: bytes.NewBuffer(mockTgz), 179 } 180 181 // install the plugin before updating 182 if err := Install(i); err != nil { 183 t.Error(err) 184 } 185 if i.Path() != home.Path("plugins", "fake-plugin") { 186 t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path()) 187 } 188 189 // Update plugin, should fail because it is not implemented 190 if err := Update(i); err == nil { 191 t.Error("update method not implemented for http installer") 192 } 193 } 194 195 func TestExtract(t *testing.T) { 196 //create a temp home 197 hh, err := ioutil.TempDir("", "helm-home-") 198 if err != nil { 199 t.Fatal(err) 200 } 201 defer os.RemoveAll(hh) 202 203 home := helmpath.Home(hh) 204 if err := os.MkdirAll(home.Plugins(), 0755); err != nil { 205 t.Fatalf("Could not create %s: %s", home.Plugins(), err) 206 } 207 208 cacheDir := filepath.Join(home.Cache(), "plugins", "plugin-key") 209 if err := os.MkdirAll(cacheDir, 0755); err != nil { 210 t.Fatalf("Could not create %s: %s", cacheDir, err) 211 } 212 213 //{"plugin.yaml", "plugin metadata up in here"}, 214 //{"README.md", "so you know what's upp"}, 215 //{"script.sh", "echo script"}, 216 217 syscall.Umask(0000) 218 219 var tarbuf bytes.Buffer 220 tw := tar.NewWriter(&tarbuf) 221 var files = []struct { 222 Name, Body string 223 Mode int64 224 }{ 225 {"../../plugin.yaml", "sneaky plugin metadata", 0600}, 226 {"README.md", "some text", 0777}, 227 } 228 for _, file := range files { 229 hdr := &tar.Header{ 230 Name: file.Name, 231 Typeflag: tar.TypeReg, 232 Mode: file.Mode, 233 Size: int64(len(file.Body)), 234 } 235 if err := tw.WriteHeader(hdr); err != nil { 236 t.Fatal(err) 237 } 238 if _, err := tw.Write([]byte(file.Body)); err != nil { 239 t.Fatal(err) 240 } 241 } 242 if err := tw.Close(); err != nil { 243 t.Fatal(err) 244 } 245 246 var buf bytes.Buffer 247 gz := gzip.NewWriter(&buf) 248 if _, err := gz.Write(tarbuf.Bytes()); err != nil { 249 t.Fatal(err) 250 } 251 gz.Close() 252 253 source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tgz" 254 extr, err := NewExtractor(source) 255 if err != nil { 256 t.Fatal(err) 257 } 258 259 if err = extr.Extract(&buf, cacheDir); err != nil { 260 t.Errorf("Did not expect error but got error: %v", err) 261 } 262 263 pluginYAMLFullPath := filepath.Join(cacheDir, "plugin.yaml") 264 if info, err := os.Stat(pluginYAMLFullPath); err != nil { 265 if os.IsNotExist(err) { 266 t.Errorf("Expected %s to exist but doesn't", pluginYAMLFullPath) 267 } else { 268 t.Error(err) 269 } 270 } else if info.Mode().Perm() != 0600 { 271 t.Errorf("Expected %s to have 0600 mode it but has %o", pluginYAMLFullPath, info.Mode().Perm()) 272 } 273 274 readmeFullPath := filepath.Join(cacheDir, "README.md") 275 if info, err := os.Stat(readmeFullPath); err != nil { 276 if os.IsNotExist(err) { 277 t.Errorf("Expected %s to exist but doesn't", readmeFullPath) 278 } else { 279 t.Error(err) 280 } 281 } else if info.Mode().Perm() != 0777 { 282 t.Errorf("Expected %s to have 0777 mode it but has %o", readmeFullPath, info.Mode().Perm()) 283 } 284 285 }