github.com/sl1pm4t/terraform@v0.6.4-0.20170725213156-870617d22df3/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  	i := &ProviderInstaller{}
   104  	versions, err := i.listProviderVersions("test")
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  
   109  	Versions(versions).Sort()
   110  
   111  	expected := []string{
   112  		"1.2.4",
   113  		"1.2.3",
   114  		"1.2.1",
   115  	}
   116  
   117  	if len(versions) != len(expected) {
   118  		t.Fatalf("Received wrong number of versions. expected: %q, got: %q", expected, versions)
   119  	}
   120  
   121  	for i, v := range versions {
   122  		if v.String() != expected[i] {
   123  			t.Fatalf("incorrect version: %q, expected %q", v, expected[i])
   124  		}
   125  	}
   126  }
   127  
   128  func TestCheckProtocolVersions(t *testing.T) {
   129  	i := &ProviderInstaller{}
   130  	if checkPlugin(i.providerURL("test", VersionStr("1.2.3").MustParse().String()), 4) {
   131  		t.Fatal("protocol version 4 is not compatible")
   132  	}
   133  
   134  	if !checkPlugin(i.providerURL("test", VersionStr("1.2.3").MustParse().String()), 3) {
   135  		t.Fatal("protocol version 3 should be compatible")
   136  	}
   137  }
   138  
   139  func TestProviderInstallerGet(t *testing.T) {
   140  	tmpDir, err := ioutil.TempDir("", "tf-plugin")
   141  	if err != nil {
   142  		t.Fatal(err)
   143  	}
   144  
   145  	defer os.RemoveAll(tmpDir)
   146  
   147  	// attempt to use an incompatible protocol version
   148  	i := &ProviderInstaller{
   149  		Dir: tmpDir,
   150  		PluginProtocolVersion: 5,
   151  		SkipVerify:            true,
   152  	}
   153  	_, err = i.Get("test", AllVersions)
   154  	if err != ErrorNoVersionCompatible {
   155  		t.Fatal("want error for incompatible version")
   156  	}
   157  
   158  	i = &ProviderInstaller{
   159  		Dir: tmpDir,
   160  		PluginProtocolVersion: 3,
   161  		SkipVerify:            true,
   162  	}
   163  
   164  	{
   165  		_, err := i.Get("test", ConstraintStr(">9.0.0").MustParse())
   166  		if err != ErrorNoSuitableVersion {
   167  			t.Fatal("want error for mismatching constraints")
   168  		}
   169  	}
   170  
   171  	{
   172  		_, err := i.Get("nonexist", AllVersions)
   173  		if err != ErrorNoSuchProvider {
   174  			t.Fatal("want error for no such provider")
   175  		}
   176  	}
   177  
   178  	gotMeta, err := i.Get("test", AllVersions)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	// we should have version 1.2.3
   184  	dest := filepath.Join(tmpDir, "terraform-provider-test_v1.2.3_x3")
   185  
   186  	wantMeta := PluginMeta{
   187  		Name:    "test",
   188  		Version: VersionStr("1.2.3"),
   189  		Path:    dest,
   190  	}
   191  	if !reflect.DeepEqual(gotMeta, wantMeta) {
   192  		t.Errorf("wrong result meta\ngot:  %#v\nwant: %#v", gotMeta, wantMeta)
   193  	}
   194  
   195  	f, err := ioutil.ReadFile(dest)
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  
   200  	// provider should have been unzipped
   201  	if string(f) != testProviderFile {
   202  		t.Fatalf("test provider contains: %q", f)
   203  	}
   204  
   205  }
   206  
   207  func TestProviderInstallerPurgeUnused(t *testing.T) {
   208  	tmpDir, err := ioutil.TempDir("", "tf-plugin")
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	defer os.RemoveAll(tmpDir)
   214  
   215  	unwantedPath := filepath.Join(tmpDir, "terraform-provider-test_v0.0.1_x2")
   216  	wantedPath := filepath.Join(tmpDir, "terraform-provider-test_v1.2.3_x3")
   217  
   218  	f, err := os.Create(unwantedPath)
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	f.Close()
   223  	f, err = os.Create(wantedPath)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	f.Close()
   228  
   229  	i := &ProviderInstaller{
   230  		Dir: tmpDir,
   231  		PluginProtocolVersion: 3,
   232  		SkipVerify:            true,
   233  	}
   234  	purged, err := i.PurgeUnused(map[string]PluginMeta{
   235  		"test": PluginMeta{
   236  			Name:    "test",
   237  			Version: VersionStr("1.2.3"),
   238  			Path:    wantedPath,
   239  		},
   240  	})
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	if got, want := purged.Count(), 1; got != want {
   246  		t.Errorf("wrong purged count %d; want %d", got, want)
   247  	}
   248  	if got, want := purged.Newest().Path, unwantedPath; got != want {
   249  		t.Errorf("wrong purged path %s; want %s", got, want)
   250  	}
   251  
   252  	files, err := ioutil.ReadDir(tmpDir)
   253  	if err != nil {
   254  		t.Fatal(err)
   255  	}
   256  
   257  	gotFilenames := make([]string, len(files))
   258  	for i, info := range files {
   259  		gotFilenames[i] = info.Name()
   260  	}
   261  	wantFilenames := []string{"terraform-provider-test_v1.2.3_x3"}
   262  
   263  	if !reflect.DeepEqual(gotFilenames, wantFilenames) {
   264  		t.Errorf("wrong filenames after purge\ngot:  %#v\nwant: %#v", gotFilenames, wantFilenames)
   265  	}
   266  }
   267  
   268  // Test fetching a provider's checksum file while verifying its signature.
   269  func TestProviderChecksum(t *testing.T) {
   270  	i := &ProviderInstaller{}
   271  
   272  	// we only need the checksum, as getter is doing the actual file comparison.
   273  	sha256sum, err := i.getProviderChecksum("template", "0.1.0")
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	// get the expected checksum for our os/arch
   279  	sumData, err := ioutil.ReadFile("testdata/terraform-provider-template_0.1.0_SHA256SUMS")
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  
   284  	expected := checksumForFile(sumData, i.providerFileName("template", "0.1.0"))
   285  
   286  	if sha256sum != expected {
   287  		t.Fatalf("expected: %s\ngot %s\n", sha256sum, expected)
   288  	}
   289  }
   290  
   291  // Test fetching a provider's checksum file witha bad signature
   292  func TestProviderChecksumBadSignature(t *testing.T) {
   293  	i := &ProviderInstaller{}
   294  
   295  	// we only need the checksum, as getter is doing the actual file comparison.
   296  	sha256sum, err := i.getProviderChecksum("badsig", "0.1.0")
   297  	if err == nil {
   298  		t.Fatal("expcted error")
   299  	}
   300  
   301  	if !strings.Contains(err.Error(), "signature") {
   302  		t.Fatal("expected signature error, got:", err)
   303  	}
   304  
   305  	if sha256sum != "" {
   306  		t.Fatal("expected no checksum, got:", sha256sum)
   307  	}
   308  }
   309  
   310  const versionList = `<!DOCTYPE html>
   311  <html>
   312  <body>
   313    <ul>
   314    <li>
   315      <a href="../">../</a>
   316    </li>
   317    <li>
   318      <a href="/terraform-provider-test/1.2.3/">terraform-provider-test_1.2.3</a>
   319    </li>
   320    <li>
   321      <a href="/terraform-provider-test/1.2.1/">terraform-provider-test_1.2.1</a>
   322    </li>
   323    <li>
   324      <a href="/terraform-provider-test/1.2.4/">terraform-provider-test_1.2.4</a>
   325    </li>
   326    </ul>
   327    <footer>
   328      Proudly fronted by <a href="https://fastly.com/?utm_source=hashicorp" target="_TOP">Fastly</a>
   329    </footer>
   330  </body>
   331  </html>
   332  `