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