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  }