github.com/hs0210/hashicorp-terraform@v0.11.12-beta1/plugin/discovery/get_test.go (about)

     1  package discovery
     2  
     3  import (
     4  	"archive/zip"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"regexp"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/mitchellh/cli"
    18  )
    19  
    20  const testProviderFile = "test provider binary"
    21  
    22  // return the directory listing for the "test" provider
    23  func testListingHandler(w http.ResponseWriter, r *http.Request) {
    24  	w.Write([]byte(versionList))
    25  }
    26  
    27  func testChecksumHandler(w http.ResponseWriter, r *http.Request) {
    28  	// this exact plugin has a signnature and checksum file
    29  	if r.URL.Path == "/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS" {
    30  		http.ServeFile(w, r, "testdata/terraform-provider-template_0.1.0_SHA256SUMS")
    31  		return
    32  	}
    33  	if r.URL.Path == "/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS.sig" {
    34  		http.ServeFile(w, r, "testdata/terraform-provider-template_0.1.0_SHA256SUMS.sig")
    35  		return
    36  	}
    37  
    38  	// this this checksum file is corrupt and doesn't match the sig
    39  	if r.URL.Path == "/terraform-provider-badsig/0.1.0/terraform-provider-badsig_0.1.0_SHA256SUMS" {
    40  		http.ServeFile(w, r, "testdata/terraform-provider-badsig_0.1.0_SHA256SUMS")
    41  		return
    42  	}
    43  	if r.URL.Path == "/terraform-provider-badsig/0.1.0/terraform-provider-badsig_0.1.0_SHA256SUMS.sig" {
    44  		http.ServeFile(w, r, "testdata/terraform-provider-badsig_0.1.0_SHA256SUMS.sig")
    45  		return
    46  	}
    47  
    48  	http.Error(w, "signtaure files not found", http.StatusNotFound)
    49  }
    50  
    51  // returns a 200 for a valid provider url, using the patch number for the
    52  // plugin protocol version.
    53  func testHandler(w http.ResponseWriter, r *http.Request) {
    54  	if r.URL.Path == "/terraform-provider-test/" {
    55  		testListingHandler(w, r)
    56  		return
    57  	}
    58  
    59  	parts := strings.Split(r.URL.Path, "/")
    60  	if len(parts) != 4 {
    61  		http.Error(w, "not found", http.StatusNotFound)
    62  		return
    63  	}
    64  
    65  	filename := parts[3]
    66  
    67  	reg := regexp.MustCompile(`(terraform-provider-test)_(\d).(\d).(\d)_([^_]+)_([^._]+).zip`)
    68  
    69  	fileParts := reg.FindStringSubmatch(filename)
    70  	if len(fileParts) != 7 {
    71  		http.Error(w, "invalid provider: "+filename, http.StatusNotFound)
    72  		return
    73  	}
    74  
    75  	w.Header().Set(protocolVersionHeader, fileParts[4])
    76  
    77  	// write a dummy file
    78  	z := zip.NewWriter(w)
    79  	fn := fmt.Sprintf("%s_v%s.%s.%s_x%s", fileParts[1], fileParts[2], fileParts[3], fileParts[4], fileParts[4])
    80  	f, err := z.Create(fn)
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  	io.WriteString(f, testProviderFile)
    85  	z.Close()
    86  }
    87  
    88  func testReleaseServer() *httptest.Server {
    89  	handler := http.NewServeMux()
    90  	handler.HandleFunc("/terraform-provider-test/", testHandler)
    91  	handler.HandleFunc("/terraform-provider-template/", testChecksumHandler)
    92  	handler.HandleFunc("/terraform-provider-badsig/", testChecksumHandler)
    93  
    94  	return httptest.NewServer(handler)
    95  }
    96  
    97  func TestMain(m *testing.M) {
    98  	server := testReleaseServer()
    99  	releaseHost = server.URL
   100  
   101  	os.Exit(m.Run())
   102  }
   103  
   104  func TestVersionListing(t *testing.T) {
   105  	i := &ProviderInstaller{}
   106  	versions, err := i.listProviderVersions("test")
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	Versions(versions).Sort()
   112  
   113  	expected := []string{
   114  		"1.2.4",
   115  		"1.2.3",
   116  		"1.2.1",
   117  	}
   118  
   119  	if len(versions) != len(expected) {
   120  		t.Fatalf("Received wrong number of versions. expected: %q, got: %q", expected, versions)
   121  	}
   122  
   123  	for i, v := range versions {
   124  		if v.String() != expected[i] {
   125  			t.Fatalf("incorrect version: %q, expected %q", v, expected[i])
   126  		}
   127  	}
   128  }
   129  
   130  func TestCheckProtocolVersions(t *testing.T) {
   131  	i := &ProviderInstaller{}
   132  	if checkPlugin(i.providerURL("test", VersionStr("1.2.3").MustParse().String()), 4) {
   133  		t.Fatal("protocol version 4 is not compatible")
   134  	}
   135  
   136  	if !checkPlugin(i.providerURL("test", VersionStr("1.2.3").MustParse().String()), 3) {
   137  		t.Fatal("protocol version 3 should be compatible")
   138  	}
   139  }
   140  
   141  func TestProviderInstallerGet(t *testing.T) {
   142  	tmpDir, err := ioutil.TempDir("", "tf-plugin")
   143  	if err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	defer os.RemoveAll(tmpDir)
   148  
   149  	// attempt to use an incompatible protocol version
   150  	i := &ProviderInstaller{
   151  		Dir:                   tmpDir,
   152  		PluginProtocolVersion: 5,
   153  		SkipVerify:            true,
   154  		Ui:                    cli.NewMockUi(),
   155  	}
   156  	_, err = i.Get("test", AllVersions)
   157  	if err != ErrorNoVersionCompatible {
   158  		t.Fatal("want error for incompatible version")
   159  	}
   160  
   161  	i = &ProviderInstaller{
   162  		Dir:                   tmpDir,
   163  		PluginProtocolVersion: 3,
   164  		SkipVerify:            true,
   165  		Ui:                    cli.NewMockUi(),
   166  	}
   167  
   168  	{
   169  		_, err := i.Get("test", ConstraintStr(">9.0.0").MustParse())
   170  		if err != ErrorNoSuitableVersion {
   171  			t.Fatal("want error for mismatching constraints")
   172  		}
   173  	}
   174  
   175  	{
   176  		_, err := i.Get("nonexist", AllVersions)
   177  		if err != ErrorNoSuchProvider {
   178  			t.Fatal("want error for no such provider")
   179  		}
   180  	}
   181  
   182  	gotMeta, err := i.Get("test", AllVersions)
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  
   187  	// we should have version 1.2.3
   188  	dest := filepath.Join(tmpDir, "terraform-provider-test_v1.2.3_x3")
   189  
   190  	wantMeta := PluginMeta{
   191  		Name:    "test",
   192  		Version: VersionStr("1.2.3"),
   193  		Path:    dest,
   194  	}
   195  	if !reflect.DeepEqual(gotMeta, wantMeta) {
   196  		t.Errorf("wrong result meta\ngot:  %#v\nwant: %#v", gotMeta, wantMeta)
   197  	}
   198  
   199  	f, err := ioutil.ReadFile(dest)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	// provider should have been unzipped
   205  	if string(f) != testProviderFile {
   206  		t.Fatalf("test provider contains: %q", f)
   207  	}
   208  
   209  }
   210  
   211  func TestProviderInstallerPurgeUnused(t *testing.T) {
   212  	tmpDir, err := ioutil.TempDir("", "tf-plugin")
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	defer os.RemoveAll(tmpDir)
   218  
   219  	unwantedPath := filepath.Join(tmpDir, "terraform-provider-test_v0.0.1_x2")
   220  	wantedPath := filepath.Join(tmpDir, "terraform-provider-test_v1.2.3_x3")
   221  
   222  	f, err := os.Create(unwantedPath)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	f.Close()
   227  	f, err = os.Create(wantedPath)
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  	f.Close()
   232  
   233  	i := &ProviderInstaller{
   234  		Dir:                   tmpDir,
   235  		PluginProtocolVersion: 3,
   236  		SkipVerify:            true,
   237  		Ui:                    cli.NewMockUi(),
   238  	}
   239  	purged, err := i.PurgeUnused(map[string]PluginMeta{
   240  		"test": PluginMeta{
   241  			Name:    "test",
   242  			Version: VersionStr("1.2.3"),
   243  			Path:    wantedPath,
   244  		},
   245  	})
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  
   250  	if got, want := purged.Count(), 1; got != want {
   251  		t.Errorf("wrong purged count %d; want %d", got, want)
   252  	}
   253  	if got, want := purged.Newest().Path, unwantedPath; got != want {
   254  		t.Errorf("wrong purged path %s; want %s", got, want)
   255  	}
   256  
   257  	files, err := ioutil.ReadDir(tmpDir)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	gotFilenames := make([]string, len(files))
   263  	for i, info := range files {
   264  		gotFilenames[i] = info.Name()
   265  	}
   266  	wantFilenames := []string{"terraform-provider-test_v1.2.3_x3"}
   267  
   268  	if !reflect.DeepEqual(gotFilenames, wantFilenames) {
   269  		t.Errorf("wrong filenames after purge\ngot:  %#v\nwant: %#v", gotFilenames, wantFilenames)
   270  	}
   271  }
   272  
   273  // Test fetching a provider's checksum file while verifying its signature.
   274  func TestProviderChecksum(t *testing.T) {
   275  	i := &ProviderInstaller{}
   276  
   277  	// we only need the checksum, as getter is doing the actual file comparison.
   278  	sha256sum, err := i.getProviderChecksum("template", "0.1.0")
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  
   283  	// get the expected checksum for our os/arch
   284  	sumData, err := ioutil.ReadFile("testdata/terraform-provider-template_0.1.0_SHA256SUMS")
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  
   289  	expected := checksumForFile(sumData, i.providerFileName("template", "0.1.0"))
   290  
   291  	if sha256sum != expected {
   292  		t.Fatalf("expected: %s\ngot %s\n", sha256sum, expected)
   293  	}
   294  }
   295  
   296  // Test fetching a provider's checksum file witha bad signature
   297  func TestProviderChecksumBadSignature(t *testing.T) {
   298  	i := &ProviderInstaller{}
   299  
   300  	// we only need the checksum, as getter is doing the actual file comparison.
   301  	sha256sum, err := i.getProviderChecksum("badsig", "0.1.0")
   302  	if err == nil {
   303  		t.Fatal("expcted error")
   304  	}
   305  
   306  	if !strings.Contains(err.Error(), "signature") {
   307  		t.Fatal("expected signature error, got:", err)
   308  	}
   309  
   310  	if sha256sum != "" {
   311  		t.Fatal("expected no checksum, got:", sha256sum)
   312  	}
   313  }
   314  
   315  const versionList = `<!DOCTYPE html>
   316  <html>
   317  <body>
   318    <ul>
   319    <li>
   320      <a href="../">../</a>
   321    </li>
   322    <li>
   323      <a href="/terraform-provider-test/1.2.3/">terraform-provider-test_1.2.3</a>
   324    </li>
   325    <li>
   326      <a href="/terraform-provider-test/1.2.1/">terraform-provider-test_1.2.1</a>
   327    </li>
   328    <li>
   329      <a href="/terraform-provider-test/1.2.4/">terraform-provider-test_1.2.4</a>
   330    </li>
   331    </ul>
   332    <footer>
   333      Proudly fronted by <a href="https://fastly.com/?utm_source=hashicorp" target="_TOP">Fastly</a>
   334    </footer>
   335  </body>
   336  </html>
   337  `