github.com/ctrox/terraform@v0.11.12-beta1/backend/remote/testing.go (about)

     1  package remote
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"testing"
    10  
    11  	tfe "github.com/hashicorp/go-tfe"
    12  	"github.com/hashicorp/terraform/backend"
    13  	"github.com/hashicorp/terraform/state/remote"
    14  	"github.com/hashicorp/terraform/svchost"
    15  	"github.com/hashicorp/terraform/svchost/auth"
    16  	"github.com/hashicorp/terraform/svchost/disco"
    17  	"github.com/mitchellh/cli"
    18  
    19  	backendLocal "github.com/hashicorp/terraform/backend/local"
    20  )
    21  
    22  const (
    23  	testCred = "test-auth-token"
    24  )
    25  
    26  var (
    27  	tfeHost  = svchost.Hostname(defaultHostname)
    28  	credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{
    29  		tfeHost: {"token": testCred},
    30  	})
    31  )
    32  
    33  func testInput(t *testing.T, answers map[string]string) *mockInput {
    34  	return &mockInput{answers: answers}
    35  }
    36  
    37  func testBackendDefault(t *testing.T) *Remote {
    38  	c := map[string]interface{}{
    39  		"organization": "hashicorp",
    40  		"workspaces": []interface{}{
    41  			map[string]interface{}{
    42  				"name": "prod",
    43  			},
    44  		},
    45  	}
    46  	return testBackend(t, c)
    47  }
    48  
    49  func testBackendNoDefault(t *testing.T) *Remote {
    50  	c := map[string]interface{}{
    51  		"organization": "hashicorp",
    52  		"workspaces": []interface{}{
    53  			map[string]interface{}{
    54  				"prefix": "my-app-",
    55  			},
    56  		},
    57  	}
    58  	return testBackend(t, c)
    59  }
    60  
    61  func testBackendNoOperations(t *testing.T) *Remote {
    62  	c := map[string]interface{}{
    63  		"organization": "no-operations",
    64  		"workspaces": []interface{}{
    65  			map[string]interface{}{
    66  				"name": "prod",
    67  			},
    68  		},
    69  	}
    70  	return testBackend(t, c)
    71  }
    72  
    73  func testRemoteClient(t *testing.T) remote.Client {
    74  	b := testBackendDefault(t)
    75  	raw, err := b.State(backend.DefaultStateName)
    76  	if err != nil {
    77  		t.Fatalf("error: %v", err)
    78  	}
    79  	s := raw.(*remote.State)
    80  	return s.Client
    81  }
    82  
    83  func testBackend(t *testing.T, c map[string]interface{}) *Remote {
    84  	s := testServer(t)
    85  	b := New(testDisco(s))
    86  
    87  	// Configure the backend so the client is created.
    88  	backend.TestBackendConfig(t, b, c)
    89  
    90  	// Get a new mock client.
    91  	mc := newMockClient()
    92  
    93  	// Replace the services we use with our mock services.
    94  	b.CLI = cli.NewMockUi()
    95  	b.client.Applies = mc.Applies
    96  	b.client.ConfigurationVersions = mc.ConfigurationVersions
    97  	b.client.Organizations = mc.Organizations
    98  	b.client.Plans = mc.Plans
    99  	b.client.PolicyChecks = mc.PolicyChecks
   100  	b.client.Runs = mc.Runs
   101  	b.client.StateVersions = mc.StateVersions
   102  	b.client.Workspaces = mc.Workspaces
   103  
   104  	// Set local to a local test backend.
   105  	b.local = testLocalBackend(t, b)
   106  
   107  	ctx := context.Background()
   108  
   109  	// Create the organization.
   110  	_, err := b.client.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
   111  		Name: tfe.String(b.organization),
   112  	})
   113  	if err != nil {
   114  		t.Fatalf("error: %v", err)
   115  	}
   116  
   117  	// Create the default workspace if required.
   118  	if b.workspace != "" {
   119  		_, err = b.client.Workspaces.Create(ctx, b.organization, tfe.WorkspaceCreateOptions{
   120  			Name: tfe.String(b.workspace),
   121  		})
   122  		if err != nil {
   123  			t.Fatalf("error: %v", err)
   124  		}
   125  	}
   126  
   127  	return b
   128  }
   129  
   130  func testLocalBackend(t *testing.T, remote *Remote) backend.Enhanced {
   131  	b := backendLocal.NewWithBackend(remote)
   132  	b.CLI = remote.CLI
   133  
   134  	// Add a test provider to the local backend.
   135  	backendLocal.TestLocalProvider(t, b, "null")
   136  
   137  	return b
   138  }
   139  
   140  // testServer returns a *httptest.Server used for local testing.
   141  func testServer(t *testing.T) *httptest.Server {
   142  	mux := http.NewServeMux()
   143  
   144  	// Respond to service discovery calls.
   145  	mux.HandleFunc("/well-known/terraform.json", func(w http.ResponseWriter, r *http.Request) {
   146  		w.Header().Set("Content-Type", "application/json")
   147  		io.WriteString(w, `{
   148    "tfe.v2.1": "/api/v2/",
   149    "versions.v1": "/v1/versions/"
   150  }`)
   151  	})
   152  
   153  	// Respond to service version constraints calls.
   154  	mux.HandleFunc("/v1/versions/", func(w http.ResponseWriter, r *http.Request) {
   155  		w.Header().Set("Content-Type", "application/json")
   156  		io.WriteString(w, `{
   157    "service": "tfe.v2.1",
   158    "product": "terraform",
   159  	"minimum": "0.11.8",
   160  	"maximum": "0.11.11"
   161  }`)
   162  	})
   163  
   164  	// Respond to the initial query to read the hashicorp org entitlements.
   165  	mux.HandleFunc("/api/v2/organizations/hashicorp/entitlement-set", func(w http.ResponseWriter, r *http.Request) {
   166  		w.Header().Set("Content-Type", "application/vnd.api+json")
   167  		io.WriteString(w, `{
   168    "data": {
   169      "id": "org-GExadygjSbKP8hsY",
   170      "type": "entitlement-sets",
   171      "attributes": {
   172        "operations": true,
   173        "private-module-registry": true,
   174        "sentinel": true,
   175        "state-storage": true,
   176        "teams": true,
   177        "vcs-integrations": true
   178      }
   179    }
   180  }`)
   181  	})
   182  
   183  	// Respond to the initial query to read the no-operations org entitlements.
   184  	mux.HandleFunc("/api/v2/organizations/no-operations/entitlement-set", func(w http.ResponseWriter, r *http.Request) {
   185  		w.Header().Set("Content-Type", "application/vnd.api+json")
   186  		io.WriteString(w, `{
   187    "data": {
   188      "id": "org-ufxa3y8jSbKP8hsT",
   189      "type": "entitlement-sets",
   190      "attributes": {
   191        "operations": false,
   192        "private-module-registry": true,
   193        "sentinel": true,
   194        "state-storage": true,
   195        "teams": true,
   196        "vcs-integrations": true
   197      }
   198    }
   199  }`)
   200  	})
   201  
   202  	// All tests that are assumed to pass will use the hashicorp organization,
   203  	// so for all other organization requests we will return a 404.
   204  	mux.HandleFunc("/api/v2/organizations/", func(w http.ResponseWriter, r *http.Request) {
   205  		w.WriteHeader(404)
   206  		io.WriteString(w, `{
   207    "errors": [
   208      {
   209        "status": "404",
   210        "title": "not found"
   211      }
   212    ]
   213  }`)
   214  	})
   215  
   216  	return httptest.NewServer(mux)
   217  }
   218  
   219  // testDisco returns a *disco.Disco mapping app.terraform.io and
   220  // localhost to a local test server.
   221  func testDisco(s *httptest.Server) *disco.Disco {
   222  	services := map[string]interface{}{
   223  		"tfe.v2.1":    fmt.Sprintf("%s/api/v2/", s.URL),
   224  		"versions.v1": fmt.Sprintf("%s/v1/versions/", s.URL),
   225  	}
   226  	d := disco.NewWithCredentialsSource(credsSrc)
   227  
   228  	d.ForceHostServices(svchost.Hostname(defaultHostname), services)
   229  	d.ForceHostServices(svchost.Hostname("localhost"), services)
   230  	return d
   231  }