update go-tfe to v0.3.16

Signed-off-by: Paul Thrasher <pthrasher@hashicorp.com>
This commit is contained in:
Paul Thrasher 2019-04-24 16:13:59 -07:00
parent 53f977bee2
commit aece05320b
No known key found for this signature in database
GPG Key ID: D4765F9CA4D82951
39 changed files with 6477 additions and 5 deletions

2
go.mod
View File

@ -55,7 +55,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.5.2
github.com/hashicorp/go-rootcerts v1.0.0 github.com/hashicorp/go-rootcerts v1.0.0
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect
github.com/hashicorp/go-tfe v0.3.14 github.com/hashicorp/go-tfe v0.3.16
github.com/hashicorp/go-uuid v1.0.1 github.com/hashicorp/go-uuid v1.0.1
github.com/hashicorp/go-version v1.1.0 github.com/hashicorp/go-version v1.1.0
github.com/hashicorp/golang-lru v0.5.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect

8
go.sum
View File

@ -189,8 +189,12 @@ github.com/hashicorp/go-slug v0.3.0 h1:L0c+AvH/J64iMNF4VqRaRku2DMTEuHioPVS7kMjWI
github.com/hashicorp/go-slug v0.3.0/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= github.com/hashicorp/go-slug v0.3.0/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-tfe v0.3.14 h1:1eWmq4RAICGufydNUWu7ahb0gtq24pN9jatD2FkdxdE= github.com/hashicorp/go-tfe v0.3.4 h1:A9pKjZMDTSGozXf2wQlWhBI7QoxCoas14Xg/TSiEAV8=
github.com/hashicorp/go-tfe v0.3.14/go.mod h1:SuPHR+OcxvzBZNye7nGPfwZTEyd3rWPfLVbCgyZPezM= github.com/hashicorp/go-tfe v0.3.4/go.mod h1:Vssg8/lwVz+PyJ/nAK97zYmXxxLe28MCIMhKo+rva1o=
github.com/hashicorp/go-tfe v0.3.15-0.20190415182703-eb3b9edefdda h1:qWY67Uh98jh4BMYSnLVIXsz2AF1hRiHG4k43wzn1NoI=
github.com/hashicorp/go-tfe v0.3.15-0.20190415182703-eb3b9edefdda/go.mod h1:SuPHR+OcxvzBZNye7nGPfwZTEyd3rWPfLVbCgyZPezM=
github.com/hashicorp/go-tfe v0.3.16 h1:GS2yv580p0co4j3FBVaC6Zahd9mxdCGehhJ0qqzFMH0=
github.com/hashicorp/go-tfe v0.3.16/go.mod h1:SuPHR+OcxvzBZNye7nGPfwZTEyd3rWPfLVbCgyZPezM=
github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=

65
vendor/github.com/hashicorp/go-tfe/apply_test.go generated vendored Normal file
View File

@ -0,0 +1,65 @@
package tfe
import (
"context"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAppliesRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createAppliedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the plan exists", func(t *testing.T) {
a, err := client.Applies.Read(ctx, rTest.Apply.ID)
require.NoError(t, err)
assert.NotEmpty(t, a.LogReadURL)
assert.Equal(t, a.Status, ApplyFinished)
assert.NotEmpty(t, a.StatusTimestamps)
})
t.Run("when the apply does not exist", func(t *testing.T) {
a, err := client.Applies.Read(ctx, "nonexisting")
assert.Nil(t, a)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid apply ID", func(t *testing.T) {
a, err := client.Applies.Read(ctx, badIdentifier)
assert.Nil(t, a)
assert.EqualError(t, err, "invalid value for apply ID")
})
}
func TestAppliesLogs(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createAppliedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the log exists", func(t *testing.T) {
a, err := client.Applies.Read(ctx, rTest.Apply.ID)
require.NoError(t, err)
logReader, err := client.Applies.Logs(ctx, a.ID)
require.NoError(t, err)
logs, err := ioutil.ReadAll(logReader)
require.NoError(t, err)
assert.Contains(t, string(logs), "1 added, 0 changed, 0 destroyed")
})
t.Run("when the log does not exist", func(t *testing.T) {
logs, err := client.Applies.Logs(ctx, "nonexisting")
assert.Nil(t, logs)
assert.Error(t, err)
})
}

View File

@ -0,0 +1,195 @@
package tfe
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestConfigurationVersionsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
cvTest1, cvTest1Cleanup := createConfigurationVersion(t, client, wTest)
defer cvTest1Cleanup()
cvTest2, cvTest2Cleanup := createConfigurationVersion(t, client, wTest)
defer cvTest2Cleanup()
t.Run("without list options", func(t *testing.T) {
options := ConfigurationVersionListOptions{}
cvl, err := client.ConfigurationVersions.List(ctx, wTest.ID, options)
require.NoError(t, err)
// We need to strip the upload URL as that is a dynamic link.
cvTest1.UploadURL = ""
cvTest2.UploadURL = ""
// And for the retrieved configuration versions as well.
for _, cv := range cvl.Items {
cv.UploadURL = ""
}
assert.Contains(t, cvl.Items, cvTest1)
assert.Contains(t, cvl.Items, cvTest2)
assert.Equal(t, 1, cvl.CurrentPage)
assert.Equal(t, 2, cvl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
options := ConfigurationVersionListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
}
cvl, err := client.ConfigurationVersions.List(ctx, wTest.ID, options)
require.NoError(t, err)
assert.Empty(t, cvl.Items)
assert.Equal(t, 999, cvl.CurrentPage)
assert.Equal(t, 2, cvl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
options := ConfigurationVersionListOptions{}
cvl, err := client.ConfigurationVersions.List(ctx, badIdentifier, options)
assert.Nil(t, cvl)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestConfigurationVersionsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
t.Run("with valid options", func(t *testing.T) {
cv, err := client.ConfigurationVersions.Create(ctx,
wTest.ID,
ConfigurationVersionCreateOptions{},
)
require.NoError(t, err)
// Get a refreshed view of the configuration version.
refreshed, err := client.ConfigurationVersions.Read(ctx, cv.ID)
require.NoError(t, err)
for _, item := range []*ConfigurationVersion{
cv,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Empty(t, item.Error)
assert.Equal(t, item.Source, ConfigurationSourceAPI)
assert.Equal(t, item.Status, ConfigurationPending)
assert.NotEmpty(t, item.UploadURL)
}
})
t.Run("with invalid workspace id", func(t *testing.T) {
cv, err := client.ConfigurationVersions.Create(
ctx,
badIdentifier,
ConfigurationVersionCreateOptions{},
)
assert.Nil(t, cv)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestConfigurationVersionsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
cvTest, cvTestCleanup := createConfigurationVersion(t, client, nil)
defer cvTestCleanup()
t.Run("when the configuration version exists", func(t *testing.T) {
cv, err := client.ConfigurationVersions.Read(ctx, cvTest.ID)
require.NoError(t, err)
// Don't compare the UploadURL because it will be generated twice in
// this test - once at creation of the configuration version, and
// again during the GET.
cvTest.UploadURL, cv.UploadURL = "", ""
assert.Equal(t, cvTest, cv)
})
t.Run("when the configuration version does not exist", func(t *testing.T) {
cv, err := client.ConfigurationVersions.Read(ctx, "nonexisting")
assert.Nil(t, cv)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid configuration version id", func(t *testing.T) {
cv, err := client.ConfigurationVersions.Read(ctx, badIdentifier)
assert.Nil(t, cv)
assert.EqualError(t, err, "invalid value for configuration version ID")
})
}
func TestConfigurationVersionsUpload(t *testing.T) {
client := testClient(t)
ctx := context.Background()
cv, cvCleanup := createConfigurationVersion(t, client, nil)
defer cvCleanup()
t.Run("with valid options", func(t *testing.T) {
err := client.ConfigurationVersions.Upload(
ctx,
cv.UploadURL,
"test-fixtures/config-version",
)
require.NoError(t, err)
// We do this is a small loop, because it can take a second
// before the upload is finished.
for i := 0; ; i++ {
refreshed, err := client.ConfigurationVersions.Read(ctx, cv.ID)
require.NoError(t, err)
if refreshed.Status == ConfigurationUploaded {
break
}
if i > 10 {
t.Fatal("Timeout waiting for the configuration version to be uploaded")
}
time.Sleep(1 * time.Second)
}
})
t.Run("without a valid upload URL", func(t *testing.T) {
err := client.ConfigurationVersions.Upload(
ctx,
cv.UploadURL[:len(cv.UploadURL)-10]+"nonexisting",
"test-fixtures/config-version",
)
assert.Error(t, err)
})
t.Run("without a valid path", func(t *testing.T) {
err := client.ConfigurationVersions.Upload(
ctx,
cv.UploadURL,
"nonexisting",
)
assert.Error(t, err)
})
}

121
vendor/github.com/hashicorp/go-tfe/cost_estimation.go generated vendored Normal file
View File

@ -0,0 +1,121 @@
package tfe
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/url"
"time"
)
// Compile-time proof of interface implementation.
var _ CostEstimations = (*costEstimations)(nil)
// CostEstimations describes all the costEstimation related methods that
// the Terraform Enterprise API supports.
//
// TFE API docs: https://www.terraform.io/docs/enterprise/api/ (TBD)
type CostEstimations interface {
// Read a costEstimation by its ID.
Read(ctx context.Context, costEstimationID string) (*CostEstimation, error)
// Logs retrieves the logs of a costEstimation.
Logs(ctx context.Context, costEstimationID string) (io.Reader, error)
}
// costEstimations implements CostEstimations.
type costEstimations struct {
client *Client
}
// CostEstimationStatus represents a costEstimation state.
type CostEstimationStatus string
//List all available costEstimation statuses.
const (
CostEstimationCanceled CostEstimationStatus = "canceled"
CostEstimationErrored CostEstimationStatus = "errored"
CostEstimationFinished CostEstimationStatus = "finished"
CostEstimationQueued CostEstimationStatus = "queued"
)
// CostEstimation represents a Terraform Enterprise costEstimation.
type CostEstimation struct {
ID string `jsonapi:"primary,cost-estimations"`
ErrorMessage string `jsonapi:"attr,error-message"`
Status CostEstimationStatus `jsonapi:"attr,status"`
StatusTimestamps *CostEstimationStatusTimestamps `jsonapi:"attr,status-timestamps"`
}
// CostEstimationStatusTimestamps holds the timestamps for individual costEstimation statuses.
type CostEstimationStatusTimestamps struct {
CanceledAt time.Time `json:"canceled-at"`
ErroredAt time.Time `json:"errored-at"`
FinishedAt time.Time `json:"finished-at"`
QueuedAt time.Time `json:"queued-at"`
}
// Read a costEstimation by its ID.
func (s *costEstimations) Read(ctx context.Context, costEstimationID string) (*CostEstimation, error) {
if !validStringID(&costEstimationID) {
return nil, errors.New("invalid value for cost estimation ID")
}
u := fmt.Sprintf("cost-estimations/%s", url.QueryEscape(costEstimationID))
req, err := s.client.newRequest("GET", u, nil)
if err != nil {
return nil, err
}
ce := &CostEstimation{}
err = s.client.do(ctx, req, ce)
if err != nil {
return nil, err
}
return ce, nil
}
// Logs retrieves the logs of a costEstimation.
func (s *costEstimations) Logs(ctx context.Context, costEstimationID string) (io.Reader, error) {
if !validStringID(&costEstimationID) {
return nil, errors.New("invalid value for cost estimation ID")
}
// Loop until the context is canceled or the cost estimation is finished
// running. The cost estimation logs are not streamed and so only available
// once the estimation is finished.
for {
// Get the costEstimation to make sure it exists.
ce, err := s.Read(ctx, costEstimationID)
if err != nil {
return nil, err
}
switch ce.Status {
case CostEstimationQueued:
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(500 * time.Millisecond):
continue
}
}
u := fmt.Sprintf("cost-estimations/%s/output", url.QueryEscape(costEstimationID))
req, err := s.client.newRequest("GET", u, nil)
if err != nil {
return nil, err
}
logs := bytes.NewBuffer(nil)
err = s.client.do(ctx, req, logs)
if err != nil {
return nil, err
}
return logs, nil
}
}

View File

@ -0,0 +1,92 @@
package tfe
import (
"context"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCostEstimationsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
// Enable cost estimation for the test organization.
orgTest, err := client.Organizations.Update(
ctx,
orgTest.Name,
OrganizationUpdateOptions{
CostEstimationEnabled: Bool(true),
},
)
require.NoError(t, err)
wTest, _ := createWorkspace(t, client, orgTest)
rTest, _ := createPlannedRun(t, client, wTest)
t.Run("when the costEstimation exists", func(t *testing.T) {
ce, err := client.CostEstimations.Read(ctx, rTest.CostEstimation.ID)
require.NoError(t, err)
assert.Equal(t, ce.Status, CostEstimationFinished)
assert.NotEmpty(t, ce.StatusTimestamps)
})
t.Run("when the costEstimation does not exist", func(t *testing.T) {
ce, err := client.CostEstimations.Read(ctx, "nonexisting")
assert.Nil(t, ce)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("with invalid costEstimation ID", func(t *testing.T) {
ce, err := client.CostEstimations.Read(ctx, badIdentifier)
assert.Nil(t, ce)
assert.EqualError(t, err, "invalid value for cost estimation ID")
})
}
func TestCostEstimationsLogs(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
// Enable cost estimation for the test organization.
orgTest, err := client.Organizations.Update(
ctx,
orgTest.Name,
OrganizationUpdateOptions{
CostEstimationEnabled: Bool(true),
},
)
require.NoError(t, err)
wTest, _ := createWorkspace(t, client, orgTest)
rTest, _ := createPlannedRun(t, client, wTest)
t.Run("when the log exists", func(t *testing.T) {
ce, err := client.CostEstimations.Read(ctx, rTest.CostEstimation.ID)
require.NoError(t, err)
logReader, err := client.CostEstimations.Logs(ctx, ce.ID)
require.NotNil(t, logReader)
require.NoError(t, err)
logs, err := ioutil.ReadAll(logReader)
require.NoError(t, err)
t.Skip("log output is likely to change")
assert.Contains(t, string(logs), "SKU")
})
t.Run("when the log does not exist", func(t *testing.T) {
logs, err := client.CostEstimations.Logs(ctx, "nonexisting")
assert.Nil(t, logs)
assert.Error(t, err)
})
}

View File

@ -0,0 +1,39 @@
package main
import (
"context"
"log"
tfe "github.com/hashicorp/go-tfe"
)
func main() {
config := &tfe.Config{
Token: "insert-your-token-here",
}
client, err := tfe.NewClient(config)
if err != nil {
log.Fatal(err)
}
// Create a context
ctx := context.Background()
// Create a new organization
options := tfe.OrganizationCreateOptions{
Name: tfe.String("example"),
Email: tfe.String("info@example.com"),
}
org, err := client.Organizations.Create(ctx, options)
if err != nil {
log.Fatal(err)
}
// Delete an organization
err = client.Organizations.Delete(ctx, org.Name)
if err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,40 @@
package main
import (
"context"
"log"
tfe "github.com/hashicorp/go-tfe"
)
func main() {
config := &tfe.Config{
Token: "insert-your-token-here",
}
client, err := tfe.NewClient(config)
if err != nil {
log.Fatal(err)
}
// Create a context
ctx := context.Background()
// Create a new workspace
w, err := client.Workspaces.Create(ctx, "org-name", tfe.WorkspaceCreateOptions{
Name: tfe.String("my-app-tst"),
})
if err != nil {
log.Fatal(err)
}
// Update the workspace
w, err = client.Workspaces.Update(ctx, "org-name", w.Name, tfe.WorkspaceUpdateOptions{
AutoApply: tfe.Bool(false),
TerraformVersion: tfe.String("0.11.1"),
WorkingDirectory: tfe.String("my-app/infra"),
})
if err != nil {
log.Fatal(err)
}
}

666
vendor/github.com/hashicorp/go-tfe/helper_test.go generated vendored Normal file
View File

@ -0,0 +1,666 @@
package tfe
import (
"context"
"crypto/md5"
"encoding/base64"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
"github.com/hashicorp/go-uuid"
)
const badIdentifier = "! / nope"
func testClient(t *testing.T) *Client {
client, err := NewClient(nil)
if err != nil {
t.Fatal(err)
}
return client
}
func createConfigurationVersion(t *testing.T, client *Client, w *Workspace) (*ConfigurationVersion, func()) {
var wCleanup func()
if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}
ctx := context.Background()
cv, err := client.ConfigurationVersions.Create(
ctx,
w.ID,
ConfigurationVersionCreateOptions{AutoQueueRuns: Bool(false)},
)
if err != nil {
t.Fatal(err)
}
return cv, func() {
if wCleanup != nil {
wCleanup()
}
}
}
func createUploadedConfigurationVersion(t *testing.T, client *Client, w *Workspace) (*ConfigurationVersion, func()) {
cv, cvCleanup := createConfigurationVersion(t, client, w)
ctx := context.Background()
err := client.ConfigurationVersions.Upload(ctx, cv.UploadURL, "test-fixtures/config-version")
if err != nil {
cvCleanup()
t.Fatal(err)
}
for i := 0; ; i++ {
cv, err = client.ConfigurationVersions.Read(ctx, cv.ID)
if err != nil {
cvCleanup()
t.Fatal(err)
}
if cv.Status == ConfigurationUploaded {
break
}
if i > 10 {
cvCleanup()
t.Fatal("Timeout waiting for the configuration version to be uploaded")
}
time.Sleep(1 * time.Second)
}
return cv, cvCleanup
}
func createNotificationConfiguration(t *testing.T, client *Client, w *Workspace) (*NotificationConfiguration, func()) {
var wCleanup func()
if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}
ctx := context.Background()
nc, err := client.NotificationConfigurations.Create(
ctx,
w.ID,
NotificationConfigurationCreateOptions{
DestinationType: NotificationDestination(NotificationDestinationTypeGeneric),
Enabled: Bool(false),
Name: String(randomString(t)),
Token: String(randomString(t)),
URL: String("http://example.com"),
Triggers: []string{NotificationTriggerCreated},
},
)
if err != nil {
t.Fatal(err)
}
return nc, func() {
if err := client.NotificationConfigurations.Delete(ctx, nc.ID); err != nil {
t.Errorf("Error destroying notification configuration! WARNING: Dangling\n"+
"resources may exist! The full error is shown below.\n\n"+
"NotificationConfiguration: %s\nError: %s", nc.ID, err)
}
if wCleanup != nil {
wCleanup()
}
}
}
func createPolicySet(t *testing.T, client *Client, org *Organization, policies []*Policy, workspaces []*Workspace) (*PolicySet, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
ctx := context.Background()
ps, err := client.PolicySets.Create(ctx, org.Name, PolicySetCreateOptions{
Name: String(randomString(t)),
Policies: policies,
Workspaces: workspaces,
})
if err != nil {
t.Fatal(err)
}
return ps, func() {
if err := client.PolicySets.Delete(ctx, ps.ID); err != nil {
t.Errorf("Error destroying policy set! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"PolicySet: %s\nError: %s", ps.ID, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createPolicy(t *testing.T, client *Client, org *Organization) (*Policy, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
name := randomString(t)
options := PolicyCreateOptions{
Name: String(name),
Enforce: []*EnforcementOptions{
{
Path: String(name + ".sentinel"),
Mode: EnforcementMode(EnforcementSoft),
},
},
}
ctx := context.Background()
p, err := client.Policies.Create(ctx, org.Name, options)
if err != nil {
t.Fatal(err)
}
return p, func() {
if err := client.Policies.Delete(ctx, p.ID); err != nil {
t.Errorf("Error destroying policy! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Policy: %s\nError: %s", p.ID, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createUploadedPolicy(t *testing.T, client *Client, pass bool, org *Organization) (*Policy, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
p, pCleanup := createPolicy(t, client, org)
ctx := context.Background()
err := client.Policies.Upload(ctx, p.ID, []byte(fmt.Sprintf("main = rule { %t }", pass)))
if err != nil {
t.Fatal(err)
}
p, err = client.Policies.Read(ctx, p.ID)
if err != nil {
t.Fatal(err)
}
return p, func() {
pCleanup()
if orgCleanup != nil {
orgCleanup()
}
}
}
func createOAuthClient(t *testing.T, client *Client, org *Organization) (*OAuthClient, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
t.Fatal("Export a valid GITHUB_TOKEN before running this test!")
}
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
HTTPURL: String("https://github.com"),
OAuthToken: String(githubToken),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
ctx := context.Background()
oc, err := client.OAuthClients.Create(ctx, org.Name, options)
if err != nil {
t.Fatal(err)
}
// This currently panics as the token will not be there when the client is
// created. To get a token, the client needs to be connected through the UI
// first. So the test using this (TestOAuthTokensList) is currently disabled.
return oc, func() {
if err := client.OAuthClients.Delete(ctx, oc.ID); err != nil {
t.Errorf("Error destroying OAuth client! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"OAuthClient: %s\nError: %s", oc.ID, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createOAuthToken(t *testing.T, client *Client, org *Organization) (*OAuthToken, func()) {
ocTest, ocTestCleanup := createOAuthClient(t, client, org)
return ocTest.OAuthTokens[0], ocTestCleanup
}
func createOrganization(t *testing.T, client *Client) (*Organization, func()) {
ctx := context.Background()
org, err := client.Organizations.Create(ctx, OrganizationCreateOptions{
Name: String("tst-" + randomString(t)),
Email: String(fmt.Sprintf("%s@tfe.local", randomString(t))),
})
if err != nil {
t.Fatal(err)
}
return org, func() {
if err := client.Organizations.Delete(ctx, org.Name); err != nil {
t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Organization: %s\nError: %s", org.Name, err)
}
}
}
func createOrganizationToken(t *testing.T, client *Client, org *Organization) (*OrganizationToken, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
ctx := context.Background()
tk, err := client.OrganizationTokens.Generate(ctx, org.Name)
if err != nil {
t.Fatal(err)
}
return tk, func() {
if err := client.OrganizationTokens.Delete(ctx, org.Name); err != nil {
t.Errorf("Error destroying organization token! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"OrganizationToken: %s\nError: %s", tk.ID, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) {
var wCleanup func()
if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}
cv, cvCleanup := createUploadedConfigurationVersion(t, client, w)
ctx := context.Background()
r, err := client.Runs.Create(ctx, RunCreateOptions{
ConfigurationVersion: cv,
Workspace: w,
})
if err != nil {
t.Fatal(err)
}
return r, func() {
if wCleanup != nil {
wCleanup()
} else {
cvCleanup()
}
}
}
func createPlannedRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) {
r, rCleanup := createRun(t, client, w)
var err error
ctx := context.Background()
for i := 0; ; i++ {
r, err = client.Runs.Read(ctx, r.ID)
if err != nil {
t.Fatal(err)
}
switch r.Status {
case RunPlanned, RunCostEstimated, RunPolicyChecked, RunPolicyOverride:
return r, rCleanup
}
if i > 45 {
rCleanup()
t.Fatal("Timeout waiting for run to be applied")
}
time.Sleep(1 * time.Second)
}
}
func createAppliedRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) {
r, rCleanup := createPlannedRun(t, client, w)
ctx := context.Background()
err := client.Runs.Apply(ctx, r.ID, RunApplyOptions{})
if err != nil {
t.Fatal(err)
}
for i := 0; ; i++ {
r, err = client.Runs.Read(ctx, r.ID)
if err != nil {
t.Fatal(err)
}
if r.Status == RunApplied {
return r, rCleanup
}
if i > 45 {
rCleanup()
t.Fatal("Timeout waiting for run to be applied")
}
time.Sleep(1 * time.Second)
}
}
func createSSHKey(t *testing.T, client *Client, org *Organization) (*SSHKey, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
ctx := context.Background()
key, err := client.SSHKeys.Create(ctx, org.Name, SSHKeyCreateOptions{
Name: String(randomString(t)),
Value: String(randomString(t)),
})
if err != nil {
t.Fatal(err)
}
return key, func() {
if err := client.SSHKeys.Delete(ctx, key.ID); err != nil {
t.Errorf("Error destroying SSH key! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"SSHKey: %s\nError: %s", key.Name, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createStateVersion(t *testing.T, client *Client, serial int64, w *Workspace) (*StateVersion, func()) {
var wCleanup func()
if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}
state, err := ioutil.ReadFile("test-fixtures/state-version/terraform.tfstate")
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
_, err = client.Workspaces.Lock(ctx, w.ID, WorkspaceLockOptions{})
if err != nil {
t.Fatal(err)
}
defer func() {
_, err := client.Workspaces.Unlock(ctx, w.ID)
if err != nil {
t.Fatal(err)
}
}()
sv, err := client.StateVersions.Create(ctx, w.ID, StateVersionCreateOptions{
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(serial),
State: String(base64.StdEncoding.EncodeToString(state)),
})
if err != nil {
t.Fatal(err)
}
return sv, func() {
// There currently isn't a way to delete a state, so we
// can only cleanup by deleting the workspace.
if wCleanup != nil {
wCleanup()
}
}
}
func createTeam(t *testing.T, client *Client, org *Organization) (*Team, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
ctx := context.Background()
tm, err := client.Teams.Create(ctx, org.Name, TeamCreateOptions{
Name: String(randomString(t)),
OrganizationAccess: &OrganizationAccessOptions{ManagePolicies: Bool(true)},
})
if err != nil {
t.Fatal(err)
}
return tm, func() {
if err := client.Teams.Delete(ctx, tm.ID); err != nil {
t.Errorf("Error destroying team! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Team: %s\nError: %s", tm.Name, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createTeamAccess(t *testing.T, client *Client, tm *Team, w *Workspace, org *Organization) (*TeamAccess, func()) {
var orgCleanup, tmCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
if tm == nil {
tm, tmCleanup = createTeam(t, client, org)
}
if w == nil {
w, _ = createWorkspace(t, client, org)
}
ctx := context.Background()
ta, err := client.TeamAccess.Add(ctx, TeamAccessAddOptions{
Access: Access(AccessAdmin),
Team: tm,
Workspace: w,
})
if err != nil {
t.Fatal(err)
}
return ta, func() {
if err := client.TeamAccess.Remove(ctx, ta.ID); err != nil {
t.Errorf("Error removing team access! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"TeamAccess: %s\nError: %s", ta.ID, err)
}
if tmCleanup != nil {
tmCleanup()
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createTeamToken(t *testing.T, client *Client, tm *Team) (*TeamToken, func()) {
var tmCleanup func()
if tm == nil {
tm, tmCleanup = createTeam(t, client, nil)
}
ctx := context.Background()
tt, err := client.TeamTokens.Generate(ctx, tm.ID)
if err != nil {
t.Fatal(err)
}
return tt, func() {
if err := client.TeamTokens.Delete(ctx, tm.ID); err != nil {
t.Errorf("Error destroying team token! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"TeamToken: %s\nError: %s", tm.ID, err)
}
if tmCleanup != nil {
tmCleanup()
}
}
}
func createVariable(t *testing.T, client *Client, w *Workspace) (*Variable, func()) {
var wCleanup func()
if w == nil {
w, wCleanup = createWorkspace(t, client, nil)
}
ctx := context.Background()
v, err := client.Variables.Create(ctx, VariableCreateOptions{
Key: String(randomString(t)),
Value: String(randomString(t)),
Category: Category(CategoryTerraform),
Workspace: w,
})
if err != nil {
t.Fatal(err)
}
return v, func() {
if err := client.Variables.Delete(ctx, v.ID); err != nil {
t.Errorf("Error destroying variable! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Variable: %s\nError: %s", v.Key, err)
}
if wCleanup != nil {
wCleanup()
}
}
}
func createWorkspace(t *testing.T, client *Client, org *Organization) (*Workspace, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
ctx := context.Background()
w, err := client.Workspaces.Create(ctx, org.Name, WorkspaceCreateOptions{
Name: String(randomString(t)),
})
if err != nil {
t.Fatal(err)
}
return w, func() {
if err := client.Workspaces.Delete(ctx, org.Name, w.Name); err != nil {
t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Workspace: %s\nError: %s", w.Name, err)
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func createWorkspaceWithVCS(t *testing.T, client *Client, org *Organization) (*Workspace, func()) {
var orgCleanup func()
if org == nil {
org, orgCleanup = createOrganization(t, client)
}
oc, ocCleanup := createOAuthToken(t, client, org)
githubIdentifier := os.Getenv("GITHUB_IDENTIFIER")
if githubIdentifier == "" {
t.Fatal("Export a valid GITHUB_IDENTIFIER before running this test!")
}
options := WorkspaceCreateOptions{
Name: String(randomString(t)),
VCSRepo: &VCSRepoOptions{
Identifier: String(githubIdentifier),
OAuthTokenID: String(oc.ID),
},
}
ctx := context.Background()
w, err := client.Workspaces.Create(ctx, org.Name, options)
if err != nil {
t.Fatal(err)
}
return w, func() {
if err := client.Workspaces.Delete(ctx, org.Name, w.Name); err != nil {
t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Workspace: %s\nError: %s", w.Name, err)
}
if ocCleanup != nil {
ocCleanup()
}
if orgCleanup != nil {
orgCleanup()
}
}
}
func randomString(t *testing.T) string {
v, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
return v
}

253
vendor/github.com/hashicorp/go-tfe/logreader_test.go generated vendored Normal file
View File

@ -0,0 +1,253 @@
package tfe
import (
"context"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"testing"
)
func testLogReader(t *testing.T, h http.HandlerFunc) (*httptest.Server, *LogReader) {
ts := httptest.NewServer(h)
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
HTTPClient: ts.Client(),
}
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
logURL, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
lr := &LogReader{
client: client,
ctx: context.Background(),
logURL: logURL,
}
return ts, lr
}
func TestLogReader_withMarkersSingle(t *testing.T) {
t.Parallel()
logReads := 0
ts, lr := testLogReader(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logReads++
switch {
case logReads == 2:
w.Write([]byte("\x02Terraform run started - logs - Terraform run finished\x03"))
}
}))
defer ts.Close()
doneReads := 0
lr.done = func() (bool, error) {
doneReads++
if logReads >= 2 {
return true, nil
}
return false, nil
}
logs, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatal(err)
}
expected := "Terraform run started - logs - Terraform run finished"
if string(logs) != expected {
t.Fatalf("expected %s, got: %s", expected, string(logs))
}
if doneReads != 1 {
t.Fatalf("expected 1 done reads, got %d reads", doneReads)
}
if logReads != 3 {
t.Fatalf("expected 3 log reads, got %d reads", logReads)
}
}
func TestLogReader_withMarkersDouble(t *testing.T) {
t.Parallel()
logReads := 0
ts, lr := testLogReader(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logReads++
switch {
case logReads == 2:
w.Write([]byte("\x02Terraform run started"))
case logReads == 3:
w.Write([]byte(" - logs - Terraform run finished\x03"))
}
}))
defer ts.Close()
doneReads := 0
lr.done = func() (bool, error) {
doneReads++
if logReads >= 3 {
return true, nil
}
return false, nil
}
logs, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatal(err)
}
expected := "Terraform run started - logs - Terraform run finished"
if string(logs) != expected {
t.Fatalf("expected %s, got: %s", expected, string(logs))
}
if doneReads != 1 {
t.Fatalf("expected 1 done reads, got %d reads", doneReads)
}
if logReads != 4 {
t.Fatalf("expected 4 log reads, got %d reads", logReads)
}
}
func TestLogReader_withMarkersMulti(t *testing.T) {
t.Parallel()
logReads := 0
ts, lr := testLogReader(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logReads++
switch {
case logReads == 2:
w.Write([]byte("\x02"))
case logReads == 3:
w.Write([]byte("Terraform run started"))
case logReads == 16:
w.Write([]byte(" - logs - "))
case logReads == 30:
w.Write([]byte("Terraform run finished"))
case logReads == 31:
w.Write([]byte("\x03"))
}
}))
defer ts.Close()
doneReads := 0
lr.done = func() (bool, error) {
doneReads++
if logReads >= 31 {
return true, nil
}
return false, nil
}
logs, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatal(err)
}
expected := "Terraform run started - logs - Terraform run finished"
if string(logs) != expected {
t.Fatalf("expected %s, got: %s", expected, string(logs))
}
if doneReads != 3 {
t.Fatalf("expected 3 done reads, got %d reads", doneReads)
}
if logReads != 31 {
t.Fatalf("expected 31 log reads, got %d reads", logReads)
}
}
func TestLogReader_withoutMarkers(t *testing.T) {
t.Parallel()
logReads := 0
ts, lr := testLogReader(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logReads++
switch {
case logReads == 2:
w.Write([]byte("Terraform run started"))
case logReads == 16:
w.Write([]byte(" - logs - "))
case logReads == 31:
w.Write([]byte("Terraform run finished"))
}
}))
defer ts.Close()
doneReads := 0
lr.done = func() (bool, error) {
doneReads++
if logReads >= 31 {
return true, nil
}
return false, nil
}
logs, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatal(err)
}
expected := "Terraform run started - logs - Terraform run finished"
if string(logs) != expected {
t.Fatalf("expected %s, got: %s", expected, string(logs))
}
if doneReads != 25 {
t.Fatalf("expected 14 done reads, got %d reads", doneReads)
}
if logReads != 32 {
t.Fatalf("expected 32 log reads, got %d reads", logReads)
}
}
func TestLogReader_withoutEndOfTextMarker(t *testing.T) {
t.Parallel()
logReads := 0
ts, lr := testLogReader(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logReads++
switch {
case logReads == 2:
w.Write([]byte("\x02"))
case logReads == 3:
w.Write([]byte("Terraform run started"))
case logReads == 16:
w.Write([]byte(" - logs - "))
case logReads == 31:
w.Write([]byte("Terraform run finished"))
}
}))
defer ts.Close()
doneReads := 0
lr.done = func() (bool, error) {
doneReads++
if logReads >= 31 {
return true, nil
}
return false, nil
}
logs, err := ioutil.ReadAll(lr)
if err != nil {
t.Fatal(err)
}
expected := "Terraform run started - logs - Terraform run finished"
if string(logs) != expected {
t.Fatalf("expected %s, got: %s", expected, string(logs))
}
if doneReads != 3 {
t.Fatalf("expected 3 done reads, got %d reads", doneReads)
}
if logReads != 42 {
t.Fatalf("expected 42 log reads, got %d reads", logReads)
}
}

View File

@ -0,0 +1,218 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNotificationConfigurationList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
ncTest1, _ := createNotificationConfiguration(t, client, wTest)
ncTest2, _ := createNotificationConfiguration(t, client, wTest)
t.Run("with a valid workspace", func(t *testing.T) {
ncl, err := client.NotificationConfigurations.List(
ctx,
wTest.ID,
NotificationConfigurationListOptions{},
)
require.NoError(t, err)
assert.Contains(t, ncl.Items, ncTest1)
assert.Contains(t, ncl.Items, ncTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, ncl.CurrentPage)
assert.Equal(t, 2, ncl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
ncl, err := client.NotificationConfigurations.List(
ctx,
wTest.ID,
NotificationConfigurationListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
},
)
require.NoError(t, err)
assert.Empty(t, ncl.Items)
assert.Equal(t, 999, ncl.CurrentPage)
assert.Equal(t, 2, ncl.TotalCount)
})
t.Run("without a valid workspace", func(t *testing.T) {
ncl, err := client.NotificationConfigurations.List(
ctx,
badIdentifier,
NotificationConfigurationListOptions{},
)
assert.Nil(t, ncl)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestNotificationConfigurationCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
t.Run("with all required values", func(t *testing.T) {
options := NotificationConfigurationCreateOptions{
DestinationType: NotificationDestination(NotificationDestinationTypeGeneric),
Enabled: Bool(false),
Name: String(randomString(t)),
Token: String(randomString(t)),
URL: String("http://example.com"),
Triggers: []string{NotificationTriggerCreated},
}
_, err := client.NotificationConfigurations.Create(ctx, wTest.ID, options)
require.NoError(t, err)
})
t.Run("without a required value", func(t *testing.T) {
options := NotificationConfigurationCreateOptions{
DestinationType: NotificationDestination(NotificationDestinationTypeGeneric),
Enabled: Bool(false),
Token: String(randomString(t)),
URL: String("http://example.com"),
Triggers: []string{NotificationTriggerCreated},
}
nc, err := client.NotificationConfigurations.Create(ctx, wTest.ID, options)
assert.Nil(t, nc)
assert.EqualError(t, err, "name is required")
})
t.Run("without a valid workspace", func(t *testing.T) {
nc, err := client.NotificationConfigurations.Create(ctx, badIdentifier, NotificationConfigurationCreateOptions{})
assert.Nil(t, nc)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestNotificationConfigurationRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
ncTest, ncTestCleanup := createNotificationConfiguration(t, client, nil)
defer ncTestCleanup()
t.Run("with a valid ID", func(t *testing.T) {
nc, err := client.NotificationConfigurations.Read(ctx, ncTest.ID)
require.NoError(t, err)
assert.Equal(t, ncTest.ID, nc.ID)
})
t.Run("when the notification configuration does not exist", func(t *testing.T) {
_, err := client.NotificationConfigurations.Read(ctx, "nonexisting")
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the notification configuration ID is invalid", func(t *testing.T) {
_, err := client.NotificationConfigurations.Read(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for notification configuration ID")
})
}
func TestNotificationConfigurationUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
ncTest, ncTestCleanup := createNotificationConfiguration(t, client, nil)
defer ncTestCleanup()
t.Run("with options", func(t *testing.T) {
options := NotificationConfigurationUpdateOptions{
Enabled: Bool(true),
Name: String("newName"),
}
nc, err := client.NotificationConfigurations.Update(ctx, ncTest.ID, options)
require.NoError(t, err)
assert.Equal(t, nc.Enabled, true)
assert.Equal(t, nc.Name, "newName")
})
t.Run("without options", func(t *testing.T) {
_, err := client.NotificationConfigurations.Update(ctx, ncTest.ID, NotificationConfigurationUpdateOptions{})
require.NoError(t, err)
})
t.Run("when the notification configuration does not exist", func(t *testing.T) {
_, err := client.NotificationConfigurations.Update(ctx, "nonexisting", NotificationConfigurationUpdateOptions{})
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the notification configuration ID is invalid", func(t *testing.T) {
_, err := client.NotificationConfigurations.Update(ctx, badIdentifier, NotificationConfigurationUpdateOptions{})
assert.EqualError(t, err, "invalid value for notification configuration ID")
})
}
func TestNotificationConfigurationDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
ncTest, _ := createNotificationConfiguration(t, client, wTest)
t.Run("with a valid ID", func(t *testing.T) {
err := client.NotificationConfigurations.Delete(ctx, ncTest.ID)
require.NoError(t, err)
_, err = client.NotificationConfigurations.Read(ctx, ncTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the notification configuration does not exist", func(t *testing.T) {
err := client.NotificationConfigurations.Delete(ctx, "nonexisting")
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the notification configuration ID is invalid", func(t *testing.T) {
err := client.NotificationConfigurations.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for notification configuration ID")
})
}
func TestNotificationConfigurationVerify(t *testing.T) {
client := testClient(t)
ctx := context.Background()
ncTest, ncTestCleanup := createNotificationConfiguration(t, client, nil)
defer ncTestCleanup()
t.Run("with a valid ID", func(t *testing.T) {
_, err := client.NotificationConfigurations.Verify(ctx, ncTest.ID)
require.NoError(t, err)
})
t.Run("when the notification configuration does not exists", func(t *testing.T) {
_, err := client.NotificationConfigurations.Verify(ctx, "nonexisting")
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the notification configuration ID is invalid", func(t *testing.T) {
_, err := client.NotificationConfigurations.Verify(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for notification configuration ID")
})
}

226
vendor/github.com/hashicorp/go-tfe/oauth_client_test.go generated vendored Normal file
View File

@ -0,0 +1,226 @@
package tfe
import (
"context"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOAuthClientsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
ocTest1, _ := createOAuthClient(t, client, orgTest)
ocTest2, _ := createOAuthClient(t, client, orgTest)
t.Run("without list options", func(t *testing.T) {
options := OAuthClientListOptions{}
ocl, err := client.OAuthClients.List(ctx, orgTest.Name, options)
require.NoError(t, err)
t.Run("the OAuth tokens relationship is decoded correcly", func(t *testing.T) {
for _, oc := range ocl.Items {
assert.Equal(t, 1, len(oc.OAuthTokens))
}
})
// We need to strip some fields before the next test.
for _, oc := range append(ocl.Items, ocTest1, ocTest2) {
oc.OAuthTokens = nil
oc.Organization = nil
}
assert.Contains(t, ocl.Items, ocTest1)
assert.Contains(t, ocl.Items, ocTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, ocl.CurrentPage)
assert.Equal(t, 2, ocl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
options := OAuthClientListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
}
ocl, err := client.OAuthClients.List(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.Empty(t, ocl.Items)
assert.Equal(t, 999, ocl.CurrentPage)
assert.Equal(t, 2, ocl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
options := OAuthClientListOptions{}
ocl, err := client.OAuthClients.List(ctx, badIdentifier, options)
assert.Nil(t, ocl)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestOAuthClientsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
t.Fatal("Export a valid GITHUB_TOKEN before running this test!")
}
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
HTTPURL: String("https://github.com"),
OAuthToken: String(githubToken),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
oc, err := client.OAuthClients.Create(ctx, orgTest.Name, options)
assert.NoError(t, err)
assert.NotEmpty(t, oc.ID)
assert.Equal(t, "https://api.github.com", oc.APIURL)
assert.Equal(t, "https://github.com", oc.HTTPURL)
assert.Equal(t, 1, len(oc.OAuthTokens))
assert.Equal(t, ServiceProviderGithub, oc.ServiceProvider)
t.Run("the organization relationship is decoded correcly", func(t *testing.T) {
assert.NotEmpty(t, oc.Organization)
})
})
t.Run("without an valid organization", func(t *testing.T) {
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
HTTPURL: String("https://github.com"),
OAuthToken: String(githubToken),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
_, err := client.OAuthClients.Create(ctx, badIdentifier, options)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("without an API URL", func(t *testing.T) {
options := OAuthClientCreateOptions{
HTTPURL: String("https://github.com"),
OAuthToken: String(githubToken),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
_, err := client.OAuthClients.Create(ctx, orgTest.Name, options)
assert.EqualError(t, err, "API URL is required")
})
t.Run("without a HTTP URL", func(t *testing.T) {
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
OAuthToken: String(githubToken),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
_, err := client.OAuthClients.Create(ctx, orgTest.Name, options)
assert.EqualError(t, err, "HTTP URL is required")
})
t.Run("without an OAuth token", func(t *testing.T) {
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
HTTPURL: String("https://github.com"),
ServiceProvider: ServiceProvider(ServiceProviderGithub),
}
_, err := client.OAuthClients.Create(ctx, orgTest.Name, options)
assert.EqualError(t, err, "OAuth token is required")
})
t.Run("without a service provider", func(t *testing.T) {
options := OAuthClientCreateOptions{
APIURL: String("https://api.github.com"),
HTTPURL: String("https://github.com"),
OAuthToken: String(githubToken),
}
_, err := client.OAuthClients.Create(ctx, orgTest.Name, options)
assert.EqualError(t, err, "service provider is required")
})
}
func TestOAuthClientsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
ocTest, ocTestCleanup := createOAuthClient(t, client, nil)
defer ocTestCleanup()
t.Run("when the OAuth client exists", func(t *testing.T) {
oc, err := client.OAuthClients.Read(ctx, ocTest.ID)
require.NoError(t, err)
assert.Equal(t, ocTest.ID, oc.ID)
assert.Equal(t, ocTest.APIURL, oc.APIURL)
assert.Equal(t, ocTest.CallbackURL, oc.CallbackURL)
assert.Equal(t, ocTest.ConnectPath, oc.ConnectPath)
assert.Equal(t, ocTest.HTTPURL, oc.HTTPURL)
assert.Equal(t, ocTest.ServiceProvider, oc.ServiceProvider)
assert.Equal(t, ocTest.ServiceProviderName, oc.ServiceProviderName)
assert.Equal(t, ocTest.OAuthTokens, oc.OAuthTokens)
})
t.Run("when the OAuth client does not exist", func(t *testing.T) {
oc, err := client.OAuthClients.Read(ctx, "nonexisting")
assert.Nil(t, oc)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("without a valid OAuth client ID", func(t *testing.T) {
oc, err := client.OAuthClients.Read(ctx, badIdentifier)
assert.Nil(t, oc)
assert.EqualError(t, err, "invalid value for OAuth client ID")
})
}
func TestOAuthClientsDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
ocTest, _ := createOAuthClient(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.OAuthClients.Delete(ctx, ocTest.ID)
require.NoError(t, err)
// Try loading the OAuth client - it should fail.
_, err = client.OAuthClients.Read(ctx, ocTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the OAuth client does not exist", func(t *testing.T) {
err := client.OAuthClients.Delete(ctx, ocTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the OAuth client ID is invalid", func(t *testing.T) {
err := client.OAuthClients.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for OAuth client ID")
})
}

189
vendor/github.com/hashicorp/go-tfe/oauth_token_test.go generated vendored Normal file
View File

@ -0,0 +1,189 @@
package tfe
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOAuthTokensList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
otTest1, _ := createOAuthToken(t, client, orgTest)
otTest2, _ := createOAuthToken(t, client, orgTest)
t.Run("without list options", func(t *testing.T) {
options := OAuthTokenListOptions{}
otl, err := client.OAuthTokens.List(ctx, orgTest.Name, options)
require.NoError(t, err)
t.Run("the OAuth client relationship is decoded correcly", func(t *testing.T) {
for _, ot := range otl.Items {
assert.NotEmpty(t, ot.OAuthClient)
}
})
// We need to strip some fields before the next test.
for _, ot := range otl.Items {
ot.CreatedAt = time.Time{}
ot.ServiceProviderUser = ""
ot.OAuthClient = nil
}
assert.Contains(t, otl.Items, otTest1)
assert.Contains(t, otl.Items, otTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, otl.CurrentPage)
assert.Equal(t, 2, otl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
options := OAuthTokenListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
}
otl, err := client.OAuthTokens.List(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.Empty(t, otl.Items)
assert.Equal(t, 999, otl.CurrentPage)
assert.Equal(t, 2, otl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
options := OAuthTokenListOptions{}
otl, err := client.OAuthTokens.List(ctx, badIdentifier, options)
assert.Nil(t, otl)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestOAuthTokensRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
otTest, otTestCleanup := createOAuthToken(t, client, nil)
defer otTestCleanup()
t.Run("when the OAuth token exists", func(t *testing.T) {
ot, err := client.OAuthTokens.Read(ctx, otTest.ID)
require.NoError(t, err)
assert.Equal(t, otTest.ID, ot.ID)
assert.NotEmpty(t, ot.OAuthClient)
})
t.Run("when the OAuth token does not exist", func(t *testing.T) {
ot, err := client.OAuthTokens.Read(ctx, "nonexisting")
assert.Nil(t, ot)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("without a valid OAuth token ID", func(t *testing.T) {
ot, err := client.OAuthTokens.Read(ctx, badIdentifier)
assert.Nil(t, ot)
assert.EqualError(t, err, "invalid value for OAuth token ID")
})
}
func TestOAuthTokensUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
otTest, otTestCleanup := createOAuthToken(t, client, nil)
defer otTestCleanup()
t.Run("before updating with an SSH key", func(t *testing.T) {
assert.False(t, otTest.HasSSHKey)
})
t.Run("without options", func(t *testing.T) {
ot, err := client.OAuthTokens.Update(ctx, otTest.ID, OAuthTokenUpdateOptions{})
require.NoError(t, err)
assert.False(t, ot.HasSSHKey)
})
t.Run("when updating with a valid SSH key", func(t *testing.T) {
dummyPrivateSSHKey := `-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDIF0s2yX7dSQQL1grdTbai1Mb7sEco6RIOz8iqrHTGqmESpu5n
d8imMkV5KadgVBJ/UvHsWpg446O3DAMYn0Y6f8dDlK7pmCEtiGVKTR1PaVRMpF8R
5Guvrmlru8Kex5ozh0pPMB15aGsIzSezCKgSs74Od9YL4smdgKyYwqsu3wIDAQAB
AoGBAKCs6+4j4icqYgBrMjBCHp4lRWCJTqtQdfrE6jv73o5F9Uu4FwupScwD5HwG
cezNtkjeP3zvxvsv+aCdGcNk60vSz4n9Nt6gEJveWFSpePYXKZ9cz/IjFLI7nSzc
1msLyE3DfUqB91s/A/aT5p0LiVDc8i4mCGDOga2OINIwqDGZAkEA/Vz8dkcqsAVW
CL1F000hWTrM6tu0V+x8Nm8CRx7wM/Gy/19PbV0t26wCVG0GXyLWsV2//huY7w5b
3AcSl5pfJQJBAMosYQXk5L4S+qivz2zmZdtyz+Ik6IZ3PwZoED32PxGSdW5rG8iP
V+iSJek5ESkS1zeXwDMnF4LeoBY9H07DiLMCQQCrHm1o2SIMpl34IxWQ4+wdHuid
yuuf4pn2Db2lGVE0VA8ICXBUtfUuA5vDN6tw/8+vFVmBn1QISVNjZOd6uwl9AkA+
jIRoAm0SsWSDlAEkvBN/VYIjgS+/il0haki8ItdYZGuYgeLSpiaYeb7o7RL2FjIn
rPd12/5WKvJ0buykvbIpAkEA5Uy3T8xQJkDGbp0+xA0yThoOYiB09lAok8I7Sv/5
dpIe8YOINN27XaojJvVpT5uBVCcZLF+G7kaMjSwCTlDx3Q==
-----END RSA PRIVATE KEY-----`
ot, err := client.OAuthTokens.Update(ctx, otTest.ID, OAuthTokenUpdateOptions{
PrivateSSHKey: String(dummyPrivateSSHKey),
})
require.NoError(t, err)
assert.Equal(t, otTest.ID, ot.ID)
assert.True(t, ot.HasSSHKey)
})
t.Run("when updating with an invalid SSH key", func(t *testing.T) {
ot, err := client.OAuthTokens.Update(ctx, otTest.ID, OAuthTokenUpdateOptions{
PrivateSSHKey: String(randomString(t)),
})
assert.Nil(t, ot)
assert.Contains(t, err.Error(), "Ssh key is invalid")
})
t.Run("without a valid policy ID", func(t *testing.T) {
ot, err := client.OAuthTokens.Update(ctx, badIdentifier, OAuthTokenUpdateOptions{})
assert.Nil(t, ot)
assert.EqualError(t, err, "invalid value for OAuth token ID")
})
}
func TestOAuthTokensDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
otTest, _ := createOAuthToken(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.OAuthTokens.Delete(ctx, otTest.ID)
require.NoError(t, err)
// Try loading the OAuth token - it should fail.
_, err = client.OAuthTokens.Read(ctx, otTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the OAuth token does not exist", func(t *testing.T) {
err := client.OAuthTokens.Delete(ctx, otTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the OAuth token ID is invalid", func(t *testing.T) {
err := client.OAuthTokens.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for OAuth token ID")
})
}

View File

@ -77,6 +77,7 @@ type OrganizationList struct {
type Organization struct { type Organization struct {
Name string `jsonapi:"primary,organizations"` Name string `jsonapi:"primary,organizations"`
CollaboratorAuthPolicy AuthPolicyType `jsonapi:"attr,collaborator-auth-policy"` CollaboratorAuthPolicy AuthPolicyType `jsonapi:"attr,collaborator-auth-policy"`
CostEstimationEnabled bool `jsonapi:"attr,cost-estimation-enabled"`
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"` CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
Email string `jsonapi:"attr,email"` Email string `jsonapi:"attr,email"`
EnterprisePlan EnterprisePlanType `jsonapi:"attr,enterprise-plan"` EnterprisePlan EnterprisePlanType `jsonapi:"attr,enterprise-plan"`
@ -167,6 +168,9 @@ type OrganizationCreateOptions struct {
// Authentication policy. // Authentication policy.
CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"` CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"`
// Enable Cost Estimation
CostEstimationEnabled *bool `jsonapi:"attr,cost-estimation-enabled,omitempty"`
// The name of the "owners" team // The name of the "owners" team
OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"` OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"`
} }
@ -248,6 +252,9 @@ type OrganizationUpdateOptions struct {
// Authentication policy. // Authentication policy.
CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"` CollaboratorAuthPolicy *AuthPolicyType `jsonapi:"attr,collaborator-auth-policy,omitempty"`
// Enable Cost Estimation
CostEstimationEnabled *bool `jsonapi:"attr,cost-estimation-enabled,omitempty"`
// The name of the "owners" team // The name of the "owners" team
OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"` OwnersTeamSAMLRoleID *string `jsonapi:"attr,owners-team-saml-role-id,omitempty"`
} }

367
vendor/github.com/hashicorp/go-tfe/organization_test.go generated vendored Normal file
View File

@ -0,0 +1,367 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOrganizationsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest1, orgTest1Cleanup := createOrganization(t, client)
defer orgTest1Cleanup()
orgTest2, orgTest2Cleanup := createOrganization(t, client)
defer orgTest2Cleanup()
t.Run("with no list options", func(t *testing.T) {
orgl, err := client.Organizations.List(ctx, OrganizationListOptions{})
require.NoError(t, err)
assert.Contains(t, orgl.Items, orgTest1)
assert.Contains(t, orgl.Items, orgTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, orgl.CurrentPage)
assert.Equal(t, 2, orgl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
orgl, err := client.Organizations.List(ctx, OrganizationListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, orgl)
assert.Equal(t, 999, orgl.CurrentPage)
assert.Equal(t, 2, orgl.TotalCount)
})
}
func TestOrganizationsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
t.Run("with valid options", func(t *testing.T) {
options := OrganizationCreateOptions{
Name: String(randomString(t)),
Email: String(randomString(t) + "@tfe.local"),
}
org, err := client.Organizations.Create(ctx, options)
require.NoError(t, err)
// Make sure we clean up the created org.
defer client.Organizations.Delete(ctx, org.Name)
assert.Equal(t, *options.Name, org.Name)
assert.Equal(t, *options.Email, org.Email)
})
t.Run("when no email is provided", func(t *testing.T) {
org, err := client.Organizations.Create(ctx, OrganizationCreateOptions{
Name: String("foo"),
})
assert.Nil(t, org)
assert.EqualError(t, err, "email is required")
})
t.Run("when no name is provided", func(t *testing.T) {
_, err := client.Organizations.Create(ctx, OrganizationCreateOptions{
Email: String("foo@bar.com"),
})
assert.EqualError(t, err, "name is required")
})
t.Run("with invalid name", func(t *testing.T) {
org, err := client.Organizations.Create(ctx, OrganizationCreateOptions{
Name: String(badIdentifier),
Email: String("foo@bar.com"),
})
assert.Nil(t, org)
assert.EqualError(t, err, "invalid value for name")
})
}
func TestOrganizationsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("when the org exists", func(t *testing.T) {
org, err := client.Organizations.Read(ctx, orgTest.Name)
require.NoError(t, err)
assert.Equal(t, orgTest, org)
t.Run("permissions are properly decoded", func(t *testing.T) {
assert.True(t, org.Permissions.CanDestroy)
})
t.Run("timestamps are populated", func(t *testing.T) {
assert.NotEmpty(t, org.CreatedAt)
assert.NotEmpty(t, org.TrialExpiresAt)
})
})
t.Run("with invalid name", func(t *testing.T) {
org, err := client.Organizations.Read(ctx, badIdentifier)
assert.Nil(t, org)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when the org does not exist", func(t *testing.T) {
_, err := client.Organizations.Read(ctx, randomString(t))
assert.Error(t, err)
})
}
func TestOrganizationsUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
t.Run("with valid options", func(t *testing.T) {
orgTest, orgTestCleanup := createOrganization(t, client)
options := OrganizationUpdateOptions{
Name: String(randomString(t)),
Email: String(randomString(t) + "@tfe.local"),
SessionTimeout: Int(3600),
SessionRemember: Int(3600),
}
org, err := client.Organizations.Update(ctx, orgTest.Name, options)
if err != nil {
orgTestCleanup()
}
require.NoError(t, err)
// Make sure we clean up the renamed org.
defer client.Organizations.Delete(ctx, org.Name)
// Also get a fresh result from the API to ensure we get the
// expected values back.
refreshed, err := client.Organizations.Read(ctx, *options.Name)
require.NoError(t, err)
for _, item := range []*Organization{
org,
refreshed,
} {
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t, *options.Email, item.Email)
assert.Equal(t, *options.SessionTimeout, item.SessionTimeout)
assert.Equal(t, *options.SessionRemember, item.SessionRemember)
}
})
t.Run("with invalid name", func(t *testing.T) {
org, err := client.Organizations.Update(ctx, badIdentifier, OrganizationUpdateOptions{})
assert.Nil(t, org)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when only updating a subset of fields", func(t *testing.T) {
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
org, err := client.Organizations.Update(ctx, orgTest.Name, OrganizationUpdateOptions{})
require.NoError(t, err)
assert.Equal(t, orgTest.Name, org.Name)
assert.Equal(t, orgTest.Email, org.Email)
})
}
func TestOrganizationsDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
t.Run("with valid options", func(t *testing.T) {
orgTest, _ := createOrganization(t, client)
err := client.Organizations.Delete(ctx, orgTest.Name)
require.NoError(t, err)
// Try fetching the org again - it should error.
_, err = client.Organizations.Read(ctx, orgTest.Name)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid name", func(t *testing.T) {
err := client.Organizations.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestOrganizationsCapacity(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest1, _ := createWorkspace(t, client, orgTest)
wTest2, _ := createWorkspace(t, client, orgTest)
wTest3, _ := createWorkspace(t, client, orgTest)
wTest4, _ := createWorkspace(t, client, orgTest)
t.Run("without queued runs", func(t *testing.T) {
c, err := client.Organizations.Capacity(ctx, orgTest.Name)
require.NoError(t, err)
assert.Equal(t, 0, c.Pending)
assert.Equal(t, 0, c.Running)
})
// For this test FRQ should be enabled and have a
// limit of 2 concurrent runs per organization.
t.Run("with queued runs", func(t *testing.T) {
_, _ = createRun(t, client, wTest1)
_, _ = createRun(t, client, wTest2)
_, _ = createRun(t, client, wTest3)
_, _ = createRun(t, client, wTest4)
c, err := client.Organizations.Capacity(ctx, orgTest.Name)
require.NoError(t, err)
assert.Equal(t, 2, c.Pending)
assert.Equal(t, 2, c.Running)
})
t.Run("with invalid name", func(t *testing.T) {
org, err := client.Organizations.Read(ctx, badIdentifier)
assert.Nil(t, org)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when the org does not exist", func(t *testing.T) {
_, err := client.Organizations.Read(ctx, randomString(t))
assert.Error(t, err)
})
}
func TestOrganizationsEntitlements(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("when the org exists", func(t *testing.T) {
entitlements, err := client.Organizations.Entitlements(ctx, orgTest.Name)
require.NoError(t, err)
assert.NotEmpty(t, entitlements.ID)
assert.True(t, entitlements.Operations)
assert.True(t, entitlements.PrivateModuleRegistry)
assert.True(t, entitlements.Sentinel)
assert.True(t, entitlements.StateStorage)
assert.True(t, entitlements.Teams)
assert.True(t, entitlements.VCSIntegrations)
})
t.Run("with invalid name", func(t *testing.T) {
entitlements, err := client.Organizations.Entitlements(ctx, badIdentifier)
assert.Nil(t, entitlements)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when the org does not exist", func(t *testing.T) {
_, err := client.Organizations.Entitlements(ctx, randomString(t))
assert.Equal(t, ErrResourceNotFound, err)
})
}
func TestOrganizationsRunQueue(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest1, _ := createWorkspace(t, client, orgTest)
wTest2, _ := createWorkspace(t, client, orgTest)
wTest3, _ := createWorkspace(t, client, orgTest)
wTest4, _ := createWorkspace(t, client, orgTest)
t.Run("without queued runs", func(t *testing.T) {
rq, err := client.Organizations.RunQueue(ctx, orgTest.Name, RunQueueOptions{})
require.NoError(t, err)
assert.Equal(t, 0, len(rq.Items))
})
// Create a couple or runs to fill the queue.
rTest1, _ := createRun(t, client, wTest1)
rTest2, _ := createRun(t, client, wTest2)
rTest3, _ := createRun(t, client, wTest3)
rTest4, _ := createRun(t, client, wTest4)
// For this test FRQ should be enabled and have a
// limit of 2 concurrent runs per organization.
t.Run("with queued runs", func(t *testing.T) {
rq, err := client.Organizations.RunQueue(ctx, orgTest.Name, RunQueueOptions{})
require.NoError(t, err)
found := []string{}
for _, r := range rq.Items {
found = append(found, r.ID)
}
assert.Contains(t, found, rTest1.ID)
assert.Contains(t, found, rTest2.ID)
assert.Contains(t, found, rTest3.ID)
assert.Contains(t, found, rTest4.ID)
})
t.Run("without queue options", func(t *testing.T) {
rq, err := client.Organizations.RunQueue(ctx, orgTest.Name, RunQueueOptions{})
require.NoError(t, err)
found := []string{}
for _, r := range rq.Items {
found = append(found, r.ID)
}
assert.Contains(t, found, rTest1.ID)
assert.Contains(t, found, rTest2.ID)
assert.Contains(t, found, rTest3.ID)
assert.Contains(t, found, rTest4.ID)
assert.Equal(t, 1, rq.CurrentPage)
assert.Equal(t, 4, rq.TotalCount)
})
t.Run("with queue options", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
rq, err := client.Organizations.RunQueue(ctx, orgTest.Name, RunQueueOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, rq.Items)
assert.Equal(t, 999, rq.CurrentPage)
assert.Equal(t, 4, rq.TotalCount)
})
t.Run("with invalid name", func(t *testing.T) {
org, err := client.Organizations.Read(ctx, badIdentifier)
assert.Nil(t, org)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when the org does not exist", func(t *testing.T) {
_, err := client.Organizations.Read(ctx, randomString(t))
assert.Error(t, err)
})
}

View File

@ -0,0 +1,93 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOrganizationTokensGenerate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
var tkToken string
t.Run("with valid options", func(t *testing.T) {
ot, err := client.OrganizationTokens.Generate(ctx, orgTest.Name)
require.NoError(t, err)
require.NotEmpty(t, ot.Token)
tkToken = ot.Token
})
t.Run("when a token already exists", func(t *testing.T) {
ot, err := client.OrganizationTokens.Generate(ctx, orgTest.Name)
require.NoError(t, err)
require.NotEmpty(t, ot.Token)
assert.NotEqual(t, tkToken, ot.Token)
})
t.Run("without valid organization", func(t *testing.T) {
ot, err := client.OrganizationTokens.Generate(ctx, badIdentifier)
assert.Nil(t, ot)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestOrganizationTokensRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
_, otTestCleanup := createOrganizationToken(t, client, orgTest)
ot, err := client.OrganizationTokens.Read(ctx, orgTest.Name)
assert.NoError(t, err)
assert.NotEmpty(t, ot)
otTestCleanup()
})
t.Run("when a token doesn't exists", func(t *testing.T) {
ot, err := client.OrganizationTokens.Read(ctx, orgTest.Name)
assert.Equal(t, ErrResourceNotFound, err)
assert.Nil(t, ot)
})
t.Run("without valid organization", func(t *testing.T) {
ot, err := client.OrganizationTokens.Read(ctx, badIdentifier)
assert.Nil(t, ot)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestOrganizationTokensDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
createOrganizationToken(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.OrganizationTokens.Delete(ctx, orgTest.Name)
assert.NoError(t, err)
})
t.Run("when a token does not exist", func(t *testing.T) {
err := client.OrganizationTokens.Delete(ctx, orgTest.Name)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without valid organization", func(t *testing.T) {
err := client.OrganizationTokens.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for organization")
})
}

66
vendor/github.com/hashicorp/go-tfe/plan_test.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
package tfe
import (
"context"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPlansRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createPlannedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the plan exists", func(t *testing.T) {
p, err := client.Plans.Read(ctx, rTest.Plan.ID)
require.NoError(t, err)
assert.True(t, p.HasChanges)
assert.NotEmpty(t, p.LogReadURL)
assert.Equal(t, p.Status, PlanFinished)
assert.NotEmpty(t, p.StatusTimestamps)
})
t.Run("when the plan does not exist", func(t *testing.T) {
p, err := client.Plans.Read(ctx, "nonexisting")
assert.Nil(t, p)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid plan ID", func(t *testing.T) {
p, err := client.Plans.Read(ctx, badIdentifier)
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for plan ID")
})
}
func TestPlansLogs(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createPlannedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the log exists", func(t *testing.T) {
p, err := client.Plans.Read(ctx, rTest.Plan.ID)
require.NoError(t, err)
logReader, err := client.Plans.Logs(ctx, p.ID)
require.NoError(t, err)
logs, err := ioutil.ReadAll(logReader)
require.NoError(t, err)
assert.Contains(t, string(logs), "1 to add, 0 to change, 0 to destroy")
})
t.Run("when the log does not exist", func(t *testing.T) {
logs, err := client.Plans.Logs(ctx, "nonexisting")
assert.Nil(t, logs)
assert.Error(t, err)
})
}

200
vendor/github.com/hashicorp/go-tfe/policy_check_test.go generated vendored Normal file
View File

@ -0,0 +1,200 @@
package tfe
import (
"context"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPolicyChecksList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest1, _ := createUploadedPolicy(t, client, true, orgTest)
pTest2, _ := createUploadedPolicy(t, client, true, orgTest)
wTest, _ := createWorkspace(t, client, orgTest)
createPolicySet(t, client, orgTest, []*Policy{pTest1, pTest2}, []*Workspace{wTest})
rTest, _ := createPlannedRun(t, client, wTest)
t.Run("without list options", func(t *testing.T) {
pcl, err := client.PolicyChecks.List(ctx, rTest.ID, PolicyCheckListOptions{})
require.NoError(t, err)
require.Equal(t, 1, len(pcl.Items))
t.Run("pagination is properly decoded", func(t *testing.T) {
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, pcl.CurrentPage)
assert.Equal(t, 1, pcl.TotalCount)
})
t.Run("permissions are properly decoded", func(t *testing.T) {
assert.NotEmpty(t, pcl.Items[0].Permissions)
})
t.Run("result is properly decoded", func(t *testing.T) {
require.NotEmpty(t, pcl.Items[0].Result)
assert.Equal(t, 2, pcl.Items[0].Result.Passed)
})
t.Run("timestamps are properly decoded", func(t *testing.T) {
assert.NotEmpty(t, pcl.Items[0].StatusTimestamps)
})
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
pcl, err := client.PolicyChecks.List(ctx, rTest.ID, PolicyCheckListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, pcl.Items)
assert.Equal(t, 999, pcl.CurrentPage)
assert.Equal(t, 1, pcl.TotalCount)
})
t.Run("without a valid run ID", func(t *testing.T) {
pcl, err := client.PolicyChecks.List(ctx, badIdentifier, PolicyCheckListOptions{})
assert.Nil(t, pcl)
assert.EqualError(t, err, "invalid value for run ID")
})
}
func TestPolicyChecksRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest, _ := createUploadedPolicy(t, client, true, orgTest)
wTest, _ := createWorkspace(t, client, orgTest)
createPolicySet(t, client, orgTest, []*Policy{pTest}, []*Workspace{wTest})
rTest, _ := createPlannedRun(t, client, wTest)
require.Equal(t, 1, len(rTest.PolicyChecks))
t.Run("when the policy check exists", func(t *testing.T) {
pc, err := client.PolicyChecks.Read(ctx, rTest.PolicyChecks[0].ID)
require.NoError(t, err)
assert.NotEmpty(t, pc.Permissions)
assert.Equal(t, PolicyScopeOrganization, pc.Scope)
assert.Equal(t, PolicyPasses, pc.Status)
assert.NotEmpty(t, pc.StatusTimestamps)
t.Run("result is properly decoded", func(t *testing.T) {
require.NotEmpty(t, pc.Result)
assert.Equal(t, 1, pc.Result.Passed)
})
})
t.Run("when the policy check does not exist", func(t *testing.T) {
pc, err := client.PolicyChecks.Read(ctx, "nonexisting")
assert.Nil(t, pc)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("without a valid policy check ID", func(t *testing.T) {
pc, err := client.PolicyChecks.Read(ctx, badIdentifier)
assert.Nil(t, pc)
assert.EqualError(t, err, "invalid value for policy check ID")
})
}
func TestPolicyChecksOverride(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("when the policy failed", func(t *testing.T) {
pTest, pTestCleanup := createUploadedPolicy(t, client, false, orgTest)
defer pTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
createPolicySet(t, client, orgTest, []*Policy{pTest}, []*Workspace{wTest})
rTest, _ := createPlannedRun(t, client, wTest)
pcl, err := client.PolicyChecks.List(ctx, rTest.ID, PolicyCheckListOptions{})
require.NoError(t, err)
require.Equal(t, 1, len(pcl.Items))
require.Equal(t, PolicySoftFailed, pcl.Items[0].Status)
pc, err := client.PolicyChecks.Override(ctx, pcl.Items[0].ID)
require.NoError(t, err)
assert.NotEmpty(t, pc.Result)
assert.Equal(t, PolicyOverridden, pc.Status)
})
t.Run("when the policy passed", func(t *testing.T) {
pTest, pTestCleanup := createUploadedPolicy(t, client, true, orgTest)
defer pTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
createPolicySet(t, client, orgTest, []*Policy{pTest}, []*Workspace{wTest})
rTest, _ := createPlannedRun(t, client, wTest)
pcl, err := client.PolicyChecks.List(ctx, rTest.ID, PolicyCheckListOptions{})
require.NoError(t, err)
require.Equal(t, 1, len(pcl.Items))
require.Equal(t, PolicyPasses, pcl.Items[0].Status)
_, err = client.PolicyChecks.Override(ctx, pcl.Items[0].ID)
assert.Error(t, err)
})
t.Run("without a valid policy check ID", func(t *testing.T) {
p, err := client.PolicyChecks.Override(ctx, badIdentifier)
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for policy check ID")
})
}
func TestPolicyChecksLogs(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest, _ := createUploadedPolicy(t, client, true, orgTest)
wTest, _ := createWorkspace(t, client, orgTest)
createPolicySet(t, client, orgTest, []*Policy{pTest}, []*Workspace{wTest})
rTest, _ := createPlannedRun(t, client, wTest)
require.Equal(t, 1, len(rTest.PolicyChecks))
t.Run("when the log exists", func(t *testing.T) {
pc, err := client.PolicyChecks.Read(ctx, rTest.PolicyChecks[0].ID)
require.NoError(t, err)
logReader, err := client.PolicyChecks.Logs(ctx, pc.ID)
require.NoError(t, err)
logs, err := ioutil.ReadAll(logReader)
require.NoError(t, err)
assert.Contains(t, string(logs), "1 policies evaluated")
})
t.Run("when the log does not exist", func(t *testing.T) {
logs, err := client.PolicyChecks.Logs(ctx, "nonexisting")
assert.Nil(t, logs)
assert.Error(t, err)
})
}

454
vendor/github.com/hashicorp/go-tfe/policy_set_test.go generated vendored Normal file
View File

@ -0,0 +1,454 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPolicySetsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
psTest1, _ := createPolicySet(t, client, orgTest, nil, nil)
psTest2, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("without list options", func(t *testing.T) {
psl, err := client.PolicySets.List(ctx, orgTest.Name, PolicySetListOptions{})
require.NoError(t, err)
assert.Contains(t, psl.Items, psTest1)
assert.Contains(t, psl.Items, psTest2)
assert.Equal(t, 1, psl.CurrentPage)
assert.Equal(t, 2, psl.TotalCount)
})
t.Run("with pagination", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
psl, err := client.PolicySets.List(ctx, orgTest.Name, PolicySetListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, psl.Items)
assert.Equal(t, 999, psl.CurrentPage)
assert.Equal(t, 2, psl.TotalCount)
})
t.Run("with search", func(t *testing.T) {
// Search by one of the policy set's names; we should get only that policy
// set and pagination data should reflect the search as well
psl, err := client.PolicySets.List(ctx, orgTest.Name, PolicySetListOptions{
Search: String(psTest1.Name),
})
require.NoError(t, err)
assert.Contains(t, psl.Items, psTest1)
assert.NotContains(t, psl.Items, psTest2)
assert.Equal(t, 1, psl.CurrentPage)
assert.Equal(t, 1, psl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
ps, err := client.PolicySets.List(ctx, badIdentifier, PolicySetListOptions{})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestPolicySetsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid attributes", func(t *testing.T) {
options := PolicySetCreateOptions{
Name: String("policy-set"),
}
ps, err := client.PolicySets.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.Equal(t, ps.Name, *options.Name)
assert.Equal(t, ps.Description, "")
assert.False(t, ps.Global)
})
t.Run("with all attributes provided", func(t *testing.T) {
options := PolicySetCreateOptions{
Name: String("global"),
Description: String("Policies in this set will be checked in ALL workspaces!"),
Global: Bool(true),
}
ps, err := client.PolicySets.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.Equal(t, ps.Name, *options.Name)
assert.Equal(t, ps.Description, *options.Description)
assert.True(t, ps.Global)
})
t.Run("with policies and workspaces provided", func(t *testing.T) {
pTest, _ := createPolicy(t, client, orgTest)
wTest, _ := createWorkspace(t, client, orgTest)
options := PolicySetCreateOptions{
Name: String("populated-policy-set"),
Policies: []*Policy{pTest},
Workspaces: []*Workspace{wTest},
}
ps, err := client.PolicySets.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
assert.Equal(t, ps.Name, *options.Name)
assert.Equal(t, ps.PolicyCount, 1)
assert.Equal(t, ps.Policies[0].ID, pTest.ID)
assert.Equal(t, ps.WorkspaceCount, 1)
assert.Equal(t, ps.Workspaces[0].ID, wTest.ID)
})
t.Run("without a name provided", func(t *testing.T) {
ps, err := client.PolicySets.Create(ctx, orgTest.Name, PolicySetCreateOptions{})
assert.Nil(t, ps)
assert.EqualError(t, err, "name is required")
})
t.Run("with an invalid name provided", func(t *testing.T) {
ps, err := client.PolicySets.Create(ctx, orgTest.Name, PolicySetCreateOptions{
Name: String("nope!"),
})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for name")
})
t.Run("without a valid organization", func(t *testing.T) {
ps, err := client.PolicySets.Create(ctx, badIdentifier, PolicySetCreateOptions{
Name: String("policy-set"),
})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestPolicySetsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
psTest, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("with a valid ID", func(t *testing.T) {
ps, err := client.PolicySets.Read(ctx, psTest.ID)
require.NoError(t, err)
assert.Equal(t, ps.ID, psTest.ID)
})
t.Run("without a valid ID", func(t *testing.T) {
ps, err := client.PolicySets.Read(ctx, badIdentifier)
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
psTest, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("with valid attributes", func(t *testing.T) {
options := PolicySetUpdateOptions{
Name: String("global"),
Description: String("Policies in this set will be checked in ALL workspaces!"),
Global: Bool(true),
}
ps, err := client.PolicySets.Update(ctx, psTest.ID, options)
require.NoError(t, err)
assert.Equal(t, ps.Name, *options.Name)
assert.Equal(t, ps.Description, *options.Description)
assert.True(t, ps.Global)
})
t.Run("with invalid attributes", func(t *testing.T) {
ps, err := client.PolicySets.Update(ctx, psTest.ID, PolicySetUpdateOptions{
Name: String("nope!"),
})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for name")
})
t.Run("without a valid ID", func(t *testing.T) {
ps, err := client.PolicySets.Update(ctx, badIdentifier, PolicySetUpdateOptions{
Name: String("policy-set"),
})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsAddPolicies(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest1, _ := createPolicy(t, client, orgTest)
pTest2, _ := createPolicy(t, client, orgTest)
psTest, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("with policies provided", func(t *testing.T) {
err := client.PolicySets.AddPolicies(ctx, psTest.ID, PolicySetAddPoliciesOptions{
Policies: []*Policy{pTest1, pTest2},
})
require.NoError(t, err)
ps, err := client.PolicySets.Read(ctx, psTest.ID)
require.NoError(t, err)
assert.Equal(t, ps.PolicyCount, 2)
ids := []string{}
for _, policy := range ps.Policies {
ids = append(ids, policy.ID)
}
assert.Contains(t, ids, pTest1.ID)
assert.Contains(t, ids, pTest2.ID)
})
t.Run("without policies provided", func(t *testing.T) {
err := client.PolicySets.AddPolicies(ctx, psTest.ID, PolicySetAddPoliciesOptions{})
assert.EqualError(t, err, "policies is required")
})
t.Run("with empty policies slice", func(t *testing.T) {
err := client.PolicySets.AddPolicies(ctx, psTest.ID, PolicySetAddPoliciesOptions{
Policies: []*Policy{},
})
assert.EqualError(t, err, "must provide at least one policy")
})
t.Run("without a valid ID", func(t *testing.T) {
err := client.PolicySets.AddPolicies(ctx, badIdentifier, PolicySetAddPoliciesOptions{
Policies: []*Policy{pTest1, pTest2},
})
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsRemovePolicies(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest1, _ := createPolicy(t, client, orgTest)
pTest2, _ := createPolicy(t, client, orgTest)
psTest, _ := createPolicySet(t, client, orgTest, []*Policy{pTest1, pTest2}, nil)
t.Run("with policies provided", func(t *testing.T) {
err := client.PolicySets.RemovePolicies(ctx, psTest.ID, PolicySetRemovePoliciesOptions{
Policies: []*Policy{pTest1, pTest2},
})
require.NoError(t, err)
ps, err := client.PolicySets.Read(ctx, psTest.ID)
require.NoError(t, err)
assert.Equal(t, 0, ps.PolicyCount)
assert.Empty(t, ps.Policies)
})
t.Run("without policies provided", func(t *testing.T) {
err := client.PolicySets.RemovePolicies(ctx, psTest.ID, PolicySetRemovePoliciesOptions{})
assert.EqualError(t, err, "policies is required")
})
t.Run("with empty policies slice", func(t *testing.T) {
err := client.PolicySets.RemovePolicies(ctx, psTest.ID, PolicySetRemovePoliciesOptions{
Policies: []*Policy{},
})
assert.EqualError(t, err, "must provide at least one policy")
})
t.Run("without a valid ID", func(t *testing.T) {
err := client.PolicySets.RemovePolicies(ctx, badIdentifier, PolicySetRemovePoliciesOptions{
Policies: []*Policy{pTest1, pTest2},
})
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsAddWorkspaces(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest1, _ := createWorkspace(t, client, orgTest)
wTest2, _ := createWorkspace(t, client, orgTest)
psTest, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("with workspaces provided", func(t *testing.T) {
err := client.PolicySets.AddWorkspaces(
ctx,
psTest.ID,
PolicySetAddWorkspacesOptions{
Workspaces: []*Workspace{wTest1, wTest2},
},
)
require.NoError(t, err)
ps, err := client.PolicySets.Read(ctx, psTest.ID)
require.NoError(t, err)
assert.Equal(t, 2, ps.WorkspaceCount)
ids := []string{}
for _, ws := range ps.Workspaces {
ids = append(ids, ws.ID)
}
assert.Contains(t, ids, wTest1.ID)
assert.Contains(t, ids, wTest2.ID)
})
t.Run("without workspaces provided", func(t *testing.T) {
err := client.PolicySets.AddWorkspaces(
ctx,
psTest.ID,
PolicySetAddWorkspacesOptions{},
)
assert.EqualError(t, err, "workspaces is required")
})
t.Run("with empty workspaces slice", func(t *testing.T) {
err := client.PolicySets.AddWorkspaces(
ctx,
psTest.ID,
PolicySetAddWorkspacesOptions{Workspaces: []*Workspace{}},
)
assert.EqualError(t, err, "must provide at least one workspace")
})
t.Run("without a valid ID", func(t *testing.T) {
err := client.PolicySets.AddWorkspaces(
ctx,
badIdentifier,
PolicySetAddWorkspacesOptions{
Workspaces: []*Workspace{wTest1, wTest2},
},
)
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsRemoveWorkspaces(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest1, _ := createWorkspace(t, client, orgTest)
wTest2, _ := createWorkspace(t, client, orgTest)
psTest, _ := createPolicySet(t, client, orgTest, nil, []*Workspace{wTest1, wTest2})
t.Run("with workspaces provided", func(t *testing.T) {
err := client.PolicySets.RemoveWorkspaces(
ctx,
psTest.ID,
PolicySetRemoveWorkspacesOptions{
Workspaces: []*Workspace{wTest1, wTest2},
},
)
require.NoError(t, err)
ps, err := client.PolicySets.Read(ctx, psTest.ID)
require.NoError(t, err)
assert.Equal(t, 0, ps.WorkspaceCount)
assert.Empty(t, ps.Workspaces)
})
t.Run("without workspaces provided", func(t *testing.T) {
err := client.PolicySets.RemoveWorkspaces(
ctx,
psTest.ID,
PolicySetRemoveWorkspacesOptions{},
)
assert.EqualError(t, err, "workspaces is required")
})
t.Run("with empty workspaces slice", func(t *testing.T) {
err := client.PolicySets.RemoveWorkspaces(
ctx,
psTest.ID,
PolicySetRemoveWorkspacesOptions{Workspaces: []*Workspace{}},
)
assert.EqualError(t, err, "must provide at least one workspace")
})
t.Run("without a valid ID", func(t *testing.T) {
err := client.PolicySets.RemoveWorkspaces(
ctx,
badIdentifier,
PolicySetRemoveWorkspacesOptions{
Workspaces: []*Workspace{wTest1, wTest2},
},
)
assert.EqualError(t, err, "invalid value for policy set ID")
})
}
func TestPolicySetsDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
psTest, _ := createPolicySet(t, client, orgTest, nil, nil)
t.Run("with valid options", func(t *testing.T) {
err := client.PolicySets.Delete(ctx, psTest.ID)
require.NoError(t, err)
// Try loading the policy - it should fail.
_, err = client.PolicySets.Read(ctx, psTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the policy does not exist", func(t *testing.T) {
err := client.PolicySets.Delete(ctx, psTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the policy ID is invalid", func(t *testing.T) {
err := client.PolicySets.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for policy set ID")
})
}

393
vendor/github.com/hashicorp/go-tfe/policy_test.go generated vendored Normal file
View File

@ -0,0 +1,393 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPoliciesList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest1, _ := createPolicy(t, client, orgTest)
pTest2, _ := createPolicy(t, client, orgTest)
t.Run("without list options", func(t *testing.T) {
pl, err := client.Policies.List(ctx, orgTest.Name, PolicyListOptions{})
require.NoError(t, err)
assert.Contains(t, pl.Items, pTest1)
assert.Contains(t, pl.Items, pTest2)
assert.Equal(t, 1, pl.CurrentPage)
assert.Equal(t, 2, pl.TotalCount)
})
t.Run("with pagination", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
pl, err := client.Policies.List(ctx, orgTest.Name, PolicyListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, pl.Items)
assert.Equal(t, 999, pl.CurrentPage)
assert.Equal(t, 2, pl.TotalCount)
})
t.Run("with search", func(t *testing.T) {
// Search by one of the policy's names; we should get only that policy
// and pagination data should reflect the search as well
pl, err := client.Policies.List(ctx, orgTest.Name, PolicyListOptions{
Search: &pTest1.Name,
})
require.NoError(t, err)
assert.Contains(t, pl.Items, pTest1)
assert.NotContains(t, pl.Items, pTest2)
assert.Equal(t, 1, pl.CurrentPage)
assert.Equal(t, 1, pl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
ps, err := client.Policies.List(ctx, badIdentifier, PolicyListOptions{})
assert.Nil(t, ps)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestPoliciesCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
name := randomString(t)
options := PolicyCreateOptions{
Name: String(name),
Description: String("A sample policy"),
Enforce: []*EnforcementOptions{
{
Path: String(name + ".sentinel"),
Mode: EnforcementMode(EnforcementSoft),
},
},
}
p, err := client.Policies.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
// Get a refreshed view from the API.
refreshed, err := client.Policies.Read(ctx, p.ID)
require.NoError(t, err)
for _, item := range []*Policy{
p,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t, *options.Description, item.Description)
}
})
t.Run("when options has an invalid name", func(t *testing.T) {
p, err := client.Policies.Create(ctx, orgTest.Name, PolicyCreateOptions{
Name: String(badIdentifier),
Enforce: []*EnforcementOptions{
{
Path: String(badIdentifier + ".sentinel"),
Mode: EnforcementMode(EnforcementSoft),
},
},
})
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for name")
})
t.Run("when options is missing name", func(t *testing.T) {
p, err := client.Policies.Create(ctx, orgTest.Name, PolicyCreateOptions{
Enforce: []*EnforcementOptions{
{
Path: String(randomString(t) + ".sentinel"),
Mode: EnforcementMode(EnforcementSoft),
},
},
})
assert.Nil(t, p)
assert.EqualError(t, err, "name is required")
})
t.Run("when options is missing an enforcement", func(t *testing.T) {
options := PolicyCreateOptions{
Name: String(randomString(t)),
}
p, err := client.Policies.Create(ctx, orgTest.Name, options)
assert.Nil(t, p)
assert.EqualError(t, err, "enforce is required")
})
t.Run("when options is missing enforcement path", func(t *testing.T) {
options := PolicyCreateOptions{
Name: String(randomString(t)),
Enforce: []*EnforcementOptions{
{
Mode: EnforcementMode(EnforcementSoft),
},
},
}
p, err := client.Policies.Create(ctx, orgTest.Name, options)
assert.Nil(t, p)
assert.EqualError(t, err, "enforcement path is required")
})
t.Run("when options is missing enforcement path", func(t *testing.T) {
name := randomString(t)
options := PolicyCreateOptions{
Name: String(name),
Enforce: []*EnforcementOptions{
{
Path: String(name + ".sentinel"),
},
},
}
p, err := client.Policies.Create(ctx, orgTest.Name, options)
assert.Nil(t, p)
assert.EqualError(t, err, "enforcement mode is required")
})
t.Run("when options has an invalid organization", func(t *testing.T) {
p, err := client.Policies.Create(ctx, badIdentifier, PolicyCreateOptions{
Name: String("foo"),
})
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestPoliciesRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest, pTestCleanup := createPolicy(t, client, orgTest)
defer pTestCleanup()
t.Run("when the policy exists without content", func(t *testing.T) {
p, err := client.Policies.Read(ctx, pTest.ID)
require.NoError(t, err)
assert.Equal(t, pTest.ID, p.ID)
assert.Equal(t, pTest.Name, p.Name)
assert.Equal(t, pTest.PolicySetCount, p.PolicySetCount)
assert.Empty(t, p.Enforce)
assert.Equal(t, pTest.Organization.Name, p.Organization.Name)
})
err := client.Policies.Upload(ctx, pTest.ID, []byte(`main = rule { true }`))
require.NoError(t, err)
t.Run("when the policy exists with content", func(t *testing.T) {
p, err := client.Policies.Read(ctx, pTest.ID)
require.NoError(t, err)
assert.Equal(t, pTest.ID, p.ID)
assert.Equal(t, pTest.Name, p.Name)
assert.Equal(t, pTest.Description, p.Description)
assert.Equal(t, pTest.PolicySetCount, p.PolicySetCount)
assert.NotEmpty(t, p.Enforce)
assert.Equal(t, pTest.Organization.Name, p.Organization.Name)
})
t.Run("when the policy does not exist", func(t *testing.T) {
p, err := client.Policies.Read(ctx, "nonexisting")
assert.Nil(t, p)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("without a valid policy ID", func(t *testing.T) {
p, err := client.Policies.Read(ctx, badIdentifier)
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for policy ID")
})
}
func TestPoliciesUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("when updating with an existing path", func(t *testing.T) {
pBefore, pBeforeCleanup := createUploadedPolicy(t, client, true, orgTest)
defer pBeforeCleanup()
require.Equal(t, 1, len(pBefore.Enforce))
pAfter, err := client.Policies.Update(ctx, pBefore.ID, PolicyUpdateOptions{
Enforce: []*EnforcementOptions{
{
Path: String(pBefore.Enforce[0].Path),
Mode: EnforcementMode(EnforcementAdvisory),
},
},
})
require.NoError(t, err)
require.Equal(t, 1, len(pAfter.Enforce))
assert.Equal(t, pBefore.ID, pAfter.ID)
assert.Equal(t, pBefore.Name, pAfter.Name)
assert.Equal(t, pBefore.Description, pAfter.Description)
assert.Equal(t, pBefore.Enforce[0].Path, pAfter.Enforce[0].Path)
assert.Equal(t, EnforcementAdvisory, pAfter.Enforce[0].Mode)
})
t.Run("when updating with a nonexisting path", func(t *testing.T) {
pBefore, pBeforeCleanup := createUploadedPolicy(t, client, true, orgTest)
defer pBeforeCleanup()
require.Equal(t, 1, len(pBefore.Enforce))
pAfter, err := client.Policies.Update(ctx, pBefore.ID, PolicyUpdateOptions{
Enforce: []*EnforcementOptions{
{
Path: String("nonexisting"),
Mode: EnforcementMode(EnforcementAdvisory),
},
},
})
require.NoError(t, err)
// Weirdly enough this is not equal as updating a nonexisting path
// causes the enforce mode to reset to the default hard-mandatory
t.Skip("see comment...")
assert.Equal(t, pBefore, pAfter)
})
t.Run("with a new description", func(t *testing.T) {
pBefore, pBeforeCleanup := createUploadedPolicy(t, client, true, orgTest)
defer pBeforeCleanup()
pAfter, err := client.Policies.Update(ctx, pBefore.ID, PolicyUpdateOptions{
Description: String("A brand new description"),
})
require.NoError(t, err)
assert.Equal(t, pBefore.Name, pAfter.Name)
assert.Equal(t, pBefore.Enforce, pAfter.Enforce)
assert.NotEqual(t, pBefore.Description, pAfter.Description)
assert.Equal(t, "A brand new description", pAfter.Description)
})
t.Run("without a valid policy ID", func(t *testing.T) {
p, err := client.Policies.Update(ctx, badIdentifier, PolicyUpdateOptions{})
assert.Nil(t, p)
assert.EqualError(t, err, "invalid value for policy ID")
})
}
func TestPoliciesDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
pTest, _ := createPolicy(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.Policies.Delete(ctx, pTest.ID)
require.NoError(t, err)
// Try loading the policy - it should fail.
_, err = client.Policies.Read(ctx, pTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the policy does not exist", func(t *testing.T) {
err := client.Policies.Delete(ctx, pTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the policy ID is invalid", func(t *testing.T) {
err := client.Policies.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for policy ID")
})
}
func TestPoliciesUpload(t *testing.T) {
client := testClient(t)
ctx := context.Background()
pTest, pTestCleanup := createPolicy(t, client, nil)
defer pTestCleanup()
t.Run("with valid options", func(t *testing.T) {
err := client.Policies.Upload(ctx, pTest.ID, []byte(`main = rule { true }`))
assert.NoError(t, err)
})
t.Run("with empty content", func(t *testing.T) {
err := client.Policies.Upload(ctx, pTest.ID, []byte{})
assert.NoError(t, err)
})
t.Run("without any content", func(t *testing.T) {
err := client.Policies.Upload(ctx, pTest.ID, nil)
assert.NoError(t, err)
})
t.Run("without a valid policy ID", func(t *testing.T) {
err := client.Policies.Upload(ctx, badIdentifier, []byte(`main = rule { true }`))
assert.EqualError(t, err, "invalid value for policy ID")
})
}
func TestPoliciesDownload(t *testing.T) {
client := testClient(t)
ctx := context.Background()
pTest, pTestCleanup := createPolicy(t, client, nil)
defer pTestCleanup()
testContent := []byte(`main = rule { true }`)
t.Run("without existing content", func(t *testing.T) {
content, err := client.Policies.Download(ctx, pTest.ID)
assert.Equal(t, ErrResourceNotFound, err)
assert.Nil(t, content)
})
t.Run("with valid options", func(t *testing.T) {
err := client.Policies.Upload(ctx, pTest.ID, testContent)
require.NoError(t, err)
content, err := client.Policies.Download(ctx, pTest.ID)
assert.NoError(t, err)
assert.Equal(t, testContent, content)
})
t.Run("without a valid policy ID", func(t *testing.T) {
content, err := client.Policies.Download(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for policy ID")
assert.Nil(t, content)
})
}

View File

@ -49,12 +49,16 @@ type RunStatus string
//List all available run statuses. //List all available run statuses.
const ( const (
RunApplied RunStatus = "applied" RunApplied RunStatus = "applied"
RunApplyQueued RunStatus = "apply_queued"
RunApplying RunStatus = "applying" RunApplying RunStatus = "applying"
RunCanceled RunStatus = "canceled" RunCanceled RunStatus = "canceled"
RunConfirmed RunStatus = "confirmed" RunConfirmed RunStatus = "confirmed"
RunCostEstimated RunStatus = "cost_estimated"
RunCostEstimating RunStatus = "cost_estimating"
RunDiscarded RunStatus = "discarded" RunDiscarded RunStatus = "discarded"
RunErrored RunStatus = "errored" RunErrored RunStatus = "errored"
RunPending RunStatus = "pending" RunPending RunStatus = "pending"
RunPlanQueued RunStatus = "plan_queued"
RunPlanned RunStatus = "planned" RunPlanned RunStatus = "planned"
RunPlannedAndFinished RunStatus = "planned_and_finished" RunPlannedAndFinished RunStatus = "planned_and_finished"
RunPlanning RunStatus = "planning" RunPlanning RunStatus = "planning"
@ -98,6 +102,7 @@ type Run struct {
// Relations // Relations
Apply *Apply `jsonapi:"relation,apply"` Apply *Apply `jsonapi:"relation,apply"`
ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"` ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"`
CostEstimation *CostEstimation `jsonapi:"relation,cost-estimation"`
Plan *Plan `jsonapi:"relation,plan"` Plan *Plan `jsonapi:"relation,plan"`
PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"` PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"`
Workspace *Workspace `jsonapi:"relation,workspace"` Workspace *Workspace `jsonapi:"relation,workspace"`
@ -274,7 +279,7 @@ func (s *runs) Cancel(ctx context.Context, runID string, options RunCancelOption
return s.client.do(ctx, req, nil) return s.client.do(ctx, req, nil)
} }
// RunCancelOptions represents the options for force-canceling a run. // RunForceCancelOptions represents the options for force-canceling a run.
type RunForceCancelOptions struct { type RunForceCancelOptions struct {
// An optional comment explaining the reason for the force-cancel. // An optional comment explaining the reason for the force-cancel.
Comment *string `json:"comment,omitempty"` Comment *string `json:"comment,omitempty"`

277
vendor/github.com/hashicorp/go-tfe/run_test.go generated vendored Normal file
View File

@ -0,0 +1,277 @@
package tfe
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRunsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
rTest1, _ := createRun(t, client, wTest)
rTest2, _ := createRun(t, client, wTest)
t.Run("without list options", func(t *testing.T) {
rl, err := client.Runs.List(ctx, wTest.ID, RunListOptions{})
require.NoError(t, err)
found := []string{}
for _, r := range rl.Items {
found = append(found, r.ID)
}
assert.Contains(t, found, rTest1.ID)
assert.Contains(t, found, rTest2.ID)
assert.Equal(t, 1, rl.CurrentPage)
assert.Equal(t, 2, rl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
rl, err := client.Runs.List(ctx, wTest.ID, RunListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, rl.Items)
assert.Equal(t, 999, rl.CurrentPage)
assert.Equal(t, 2, rl.TotalCount)
})
t.Run("without a valid workspace ID", func(t *testing.T) {
rl, err := client.Runs.List(ctx, badIdentifier, RunListOptions{})
assert.Nil(t, rl)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestRunsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
cvTest, _ := createUploadedConfigurationVersion(t, client, wTest)
t.Run("without a configuration version", func(t *testing.T) {
options := RunCreateOptions{
Workspace: wTest,
}
_, err := client.Runs.Create(ctx, options)
assert.NoError(t, err)
})
t.Run("with a configuration version", func(t *testing.T) {
options := RunCreateOptions{
ConfigurationVersion: cvTest,
Workspace: wTest,
}
r, err := client.Runs.Create(ctx, options)
require.NoError(t, err)
assert.Equal(t, cvTest.ID, r.ConfigurationVersion.ID)
})
t.Run("without a workspace", func(t *testing.T) {
r, err := client.Runs.Create(ctx, RunCreateOptions{})
assert.Nil(t, r)
assert.EqualError(t, err, "workspace is required")
})
t.Run("with additional attributes", func(t *testing.T) {
options := RunCreateOptions{
Message: String("yo"),
Workspace: wTest,
}
r, err := client.Runs.Create(ctx, options)
require.NoError(t, err)
assert.Equal(t, *options.Message, r.Message)
})
}
func TestRunsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createPlannedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the run exists", func(t *testing.T) {
r, err := client.Runs.Read(ctx, rTest.ID)
assert.NoError(t, err)
assert.Equal(t, rTest, r)
})
t.Run("when the run does not exist", func(t *testing.T) {
r, err := client.Runs.Read(ctx, "nonexisting")
assert.Nil(t, r)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid run ID", func(t *testing.T) {
r, err := client.Runs.Read(ctx, badIdentifier)
assert.Nil(t, r)
assert.EqualError(t, err, "invalid value for run ID")
})
}
func TestRunsApply(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createPlannedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the run exists", func(t *testing.T) {
err := client.Runs.Apply(ctx, rTest.ID, RunApplyOptions{})
assert.NoError(t, err)
})
t.Run("when the run does not exist", func(t *testing.T) {
err := client.Runs.Apply(ctx, "nonexisting", RunApplyOptions{})
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid run ID", func(t *testing.T) {
err := client.Runs.Apply(ctx, badIdentifier, RunApplyOptions{})
assert.EqualError(t, err, "invalid value for run ID")
})
}
func TestRunsCancel(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
// We need to create 2 runs here. The first run will automatically
// be planned so that one cannot be cancelled. The second one will
// be pending until the first one is confirmed or discarded, so we
// can cancel that one.
_, _ = createRun(t, client, wTest)
rTest2, _ := createRun(t, client, wTest)
t.Run("when the run exists", func(t *testing.T) {
err := client.Runs.Cancel(ctx, rTest2.ID, RunCancelOptions{})
assert.NoError(t, err)
})
t.Run("when the run does not exist", func(t *testing.T) {
err := client.Runs.Cancel(ctx, "nonexisting", RunCancelOptions{})
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid run ID", func(t *testing.T) {
err := client.Runs.Cancel(ctx, badIdentifier, RunCancelOptions{})
assert.EqualError(t, err, "invalid value for run ID")
})
}
func TestRunsForceCancel(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
// We need to create 2 runs here. The first run will automatically
// be planned so that one cannot be cancelled. The second one will
// be pending until the first one is confirmed or discarded, so we
// can cancel that one.
_, _ = createRun(t, client, wTest)
rTest, _ := createRun(t, client, wTest)
t.Run("run is not force-cancelable", func(t *testing.T) {
assert.False(t, rTest.Actions.IsForceCancelable)
})
t.Run("user is allowed to force-cancel", func(t *testing.T) {
assert.True(t, rTest.Permissions.CanForceCancel)
})
t.Run("after a normal cancel", func(t *testing.T) {
// Request the normal cancel
err := client.Runs.Cancel(ctx, rTest.ID, RunCancelOptions{})
require.NoError(t, err)
for i := 1; ; i++ {
// Refresh the view of the run
rTest, err = client.Runs.Read(ctx, rTest.ID)
require.NoError(t, err)
// Check if the timestamp is present.
if !rTest.ForceCancelAvailableAt.IsZero() {
break
}
if i > 30 {
t.Fatal("Timeout waiting for run to be canceled")
}
time.Sleep(time.Second)
}
t.Run("force-cancel-available-at timestamp is present", func(t *testing.T) {
assert.True(t, rTest.ForceCancelAvailableAt.After(time.Now()))
})
// This test case is minimal because a force-cancel is not needed in
// any normal circumstance. Only if Terraform encounters unexpected
// errors or behaves abnormally should this functionality be required.
// Force-cancel only becomes available if a normal cancel is performed
// first, and the desired canceled state is not reached within a pre-
// determined amount of time (see
// https://www.terraform.io/docs/enterprise/api/run.html#forcefully-cancel-a-run).
})
t.Run("when the run does not exist", func(t *testing.T) {
err := client.Runs.ForceCancel(ctx, "nonexisting", RunForceCancelOptions{})
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid run ID", func(t *testing.T) {
err := client.Runs.ForceCancel(ctx, badIdentifier, RunForceCancelOptions{})
assert.EqualError(t, err, "invalid value for run ID")
})
}
func TestRunsDiscard(t *testing.T) {
client := testClient(t)
ctx := context.Background()
rTest, rTestCleanup := createPlannedRun(t, client, nil)
defer rTestCleanup()
t.Run("when the run exists", func(t *testing.T) {
err := client.Runs.Discard(ctx, rTest.ID, RunDiscardOptions{})
assert.NoError(t, err)
})
t.Run("when the run does not exist", func(t *testing.T) {
err := client.Runs.Discard(ctx, "nonexisting", RunDiscardOptions{})
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid run ID", func(t *testing.T) {
err := client.Runs.Discard(ctx, badIdentifier, RunDiscardOptions{})
assert.EqualError(t, err, "invalid value for run ID")
})
}

219
vendor/github.com/hashicorp/go-tfe/ssh_key_test.go generated vendored Normal file
View File

@ -0,0 +1,219 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSSHKeysList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
kTest1, _ := createSSHKey(t, client, orgTest)
kTest2, _ := createSSHKey(t, client, orgTest)
t.Run("without list options", func(t *testing.T) {
kl, err := client.SSHKeys.List(ctx, orgTest.Name, SSHKeyListOptions{})
require.NoError(t, err)
assert.Contains(t, kl.Items, kTest1)
assert.Contains(t, kl.Items, kTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, kl.CurrentPage)
assert.Equal(t, 2, kl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
kl, err := client.SSHKeys.List(ctx, orgTest.Name, SSHKeyListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, kl.Items)
assert.Equal(t, 999, kl.CurrentPage)
assert.Equal(t, 2, kl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
kl, err := client.SSHKeys.List(ctx, badIdentifier, SSHKeyListOptions{})
assert.Nil(t, kl)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestSSHKeysCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := SSHKeyCreateOptions{
Name: String(randomString(t)),
Value: String(randomString(t)),
}
k, err := client.SSHKeys.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
// Get a refreshed view from the API.
refreshed, err := client.SSHKeys.Read(ctx, k.ID)
require.NoError(t, err)
for _, item := range []*SSHKey{
k,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Name, item.Name)
}
})
t.Run("when options is missing name", func(t *testing.T) {
k, err := client.SSHKeys.Create(ctx, "foo", SSHKeyCreateOptions{
Value: String(randomString(t)),
})
assert.Nil(t, k)
assert.EqualError(t, err, "name is required")
})
t.Run("when options is missing value", func(t *testing.T) {
k, err := client.SSHKeys.Create(ctx, "foo", SSHKeyCreateOptions{
Name: String(randomString(t)),
})
assert.Nil(t, k)
assert.EqualError(t, err, "value is required")
})
t.Run("when options has an invalid organization", func(t *testing.T) {
k, err := client.SSHKeys.Create(ctx, badIdentifier, SSHKeyCreateOptions{
Name: String("foo"),
})
assert.Nil(t, k)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestSSHKeysRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
kTest, _ := createSSHKey(t, client, orgTest)
t.Run("when the SSH key exists", func(t *testing.T) {
k, err := client.SSHKeys.Read(ctx, kTest.ID)
require.NoError(t, err)
assert.Equal(t, kTest, k)
})
t.Run("when the SSH key does not exist", func(t *testing.T) {
k, err := client.SSHKeys.Read(ctx, "nonexisting")
assert.Nil(t, k)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without a valid SSH key ID", func(t *testing.T) {
k, err := client.SSHKeys.Read(ctx, badIdentifier)
assert.Nil(t, k)
assert.EqualError(t, err, "invalid value for SSH key ID")
})
}
func TestSSHKeysUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
kBefore, kTestCleanup := createSSHKey(t, client, orgTest)
defer kTestCleanup()
kAfter, err := client.SSHKeys.Update(ctx, kBefore.ID, SSHKeyUpdateOptions{
Name: String(randomString(t)),
Value: String(randomString(t)),
})
require.NoError(t, err)
assert.Equal(t, kBefore.ID, kAfter.ID)
assert.NotEqual(t, kBefore.Name, kAfter.Name)
})
t.Run("when updating the name", func(t *testing.T) {
kBefore, kTestCleanup := createSSHKey(t, client, orgTest)
defer kTestCleanup()
kAfter, err := client.SSHKeys.Update(ctx, kBefore.ID, SSHKeyUpdateOptions{
Name: String("updated-key-name"),
})
require.NoError(t, err)
assert.Equal(t, kBefore.ID, kAfter.ID)
assert.Equal(t, "updated-key-name", kAfter.Name)
})
t.Run("when updating the value", func(t *testing.T) {
kBefore, kTestCleanup := createSSHKey(t, client, orgTest)
defer kTestCleanup()
kAfter, err := client.SSHKeys.Update(ctx, kBefore.ID, SSHKeyUpdateOptions{
Value: String("updated-key-value"),
})
require.NoError(t, err)
assert.Equal(t, kBefore.ID, kAfter.ID)
assert.Equal(t, kBefore.Name, kAfter.Name)
})
t.Run("without a valid SSH key ID", func(t *testing.T) {
w, err := client.SSHKeys.Update(ctx, badIdentifier, SSHKeyUpdateOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for SSH key ID")
})
}
func TestSSHKeysDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
kTest, _ := createSSHKey(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.SSHKeys.Delete(ctx, kTest.ID)
require.NoError(t, err)
// Try loading the SSH key - it should fail.
_, err = client.SSHKeys.Read(ctx, kTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the SSH key does not exist", func(t *testing.T) {
err := client.SSHKeys.Delete(ctx, kTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the SSH key ID is invalid", func(t *testing.T) {
err := client.SSHKeys.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for SSH key ID")
})
}

View File

@ -0,0 +1,350 @@
package tfe
import (
"context"
"crypto/md5"
"encoding/base64"
"fmt"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestStateVersionsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, wTestCleanup := createWorkspace(t, client, orgTest)
defer wTestCleanup()
svTest1, _ := createStateVersion(t, client, 0, wTest)
svTest2, _ := createStateVersion(t, client, 1, wTest)
t.Run("without list options", func(t *testing.T) {
options := StateVersionListOptions{
Organization: String(orgTest.Name),
Workspace: String(wTest.Name),
}
svl, err := client.StateVersions.List(ctx, options)
require.NoError(t, err)
// We need to strip the upload URL as that is a dynamic link.
svTest1.DownloadURL = ""
svTest2.DownloadURL = ""
// And for the retrieved configuration versions as well.
for _, sv := range svl.Items {
sv.DownloadURL = ""
}
assert.Contains(t, svl.Items, svTest1)
assert.Contains(t, svl.Items, svTest2)
assert.Equal(t, 1, svl.CurrentPage)
assert.Equal(t, 2, svl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
options := StateVersionListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
Organization: String(orgTest.Name),
Workspace: String(wTest.Name),
}
svl, err := client.StateVersions.List(ctx, options)
require.NoError(t, err)
assert.Empty(t, svl.Items)
assert.Equal(t, 999, svl.CurrentPage)
assert.Equal(t, 2, svl.TotalCount)
})
t.Run("without an organization", func(t *testing.T) {
options := StateVersionListOptions{
Workspace: String(wTest.Name),
}
svl, err := client.StateVersions.List(ctx, options)
assert.Nil(t, svl)
assert.EqualError(t, err, "organization is required")
})
t.Run("without a workspace", func(t *testing.T) {
options := StateVersionListOptions{
Organization: String(orgTest.Name),
}
svl, err := client.StateVersions.List(ctx, options)
assert.Nil(t, svl)
assert.EqualError(t, err, "workspace is required")
})
}
func TestStateVersionsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
state, err := ioutil.ReadFile("test-fixtures/state-version/terraform.tfstate")
if err != nil {
t.Fatal(err)
}
t.Run("with valid options", func(t *testing.T) {
ctx := context.Background()
_, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
if err != nil {
t.Fatal(err)
}
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
Lineage: String("741c4949-60b9-5bb1-5bf8-b14f4bb14af3"),
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(1),
State: String(base64.StdEncoding.EncodeToString(state)),
})
require.NoError(t, err)
// Get a refreshed view of the configuration version.
refreshed, err := client.StateVersions.Read(ctx, sv.ID)
require.NoError(t, err)
_, err = client.Workspaces.Unlock(ctx, wTest.ID)
if err != nil {
t.Fatal(err)
}
for _, item := range []*StateVersion{
sv,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, int64(1), item.Serial)
assert.NotEmpty(t, item.CreatedAt)
assert.NotEmpty(t, item.DownloadURL)
}
})
t.Run("with the force flag set", func(t *testing.T) {
ctx := context.Background()
_, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
if err != nil {
t.Fatal(err)
}
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
Lineage: String("741c4949-60b9-5bb1-5bf8-b14f4bb14af3"),
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(1),
State: String(base64.StdEncoding.EncodeToString(state)),
})
require.NoError(t, err)
sv, err = client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
Lineage: String("821c4747-a0b9-3bd1-8bf3-c14f4bb14be7"),
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(2),
State: String(base64.StdEncoding.EncodeToString(state)),
Force: Bool(true),
})
require.NoError(t, err)
// Get a refreshed view of the configuration version.
refreshed, err := client.StateVersions.Read(ctx, sv.ID)
require.NoError(t, err)
_, err = client.Workspaces.Unlock(ctx, wTest.ID)
if err != nil {
t.Fatal(err)
}
for _, item := range []*StateVersion{
sv,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, int64(2), item.Serial)
assert.NotEmpty(t, item.CreatedAt)
assert.NotEmpty(t, item.DownloadURL)
}
})
t.Run("with a run to associate with", func(t *testing.T) {
t.Skip("This can only be tested with the run specific token")
rTest, _ := createRun(t, client, wTest)
ctx := context.Background()
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(0),
State: String(base64.StdEncoding.EncodeToString(state)),
Run: rTest,
})
require.NoError(t, err)
require.NotEmpty(t, sv.Run)
// Get a refreshed view of the configuration version.
refreshed, err := client.StateVersions.Read(ctx, sv.ID)
require.NoError(t, err)
require.NotEmpty(t, refreshed.Run)
for _, item := range []*StateVersion{
sv,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, int64(0), item.Serial)
assert.NotEmpty(t, item.CreatedAt)
assert.NotEmpty(t, item.DownloadURL)
assert.Equal(t, rTest.ID, item.Run.ID)
}
})
t.Run("without md5 hash", func(t *testing.T) {
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
Serial: Int64(0),
State: String(base64.StdEncoding.EncodeToString(state)),
})
assert.Nil(t, sv)
assert.EqualError(t, err, "MD5 is required")
})
t.Run("withous serial", func(t *testing.T) {
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
State: String(base64.StdEncoding.EncodeToString(state)),
})
assert.Nil(t, sv)
assert.EqualError(t, err, "serial is required")
})
t.Run("without state", func(t *testing.T) {
sv, err := client.StateVersions.Create(ctx, wTest.ID, StateVersionCreateOptions{
MD5: String(fmt.Sprintf("%x", md5.Sum(state))),
Serial: Int64(0),
})
assert.Nil(t, sv)
assert.EqualError(t, err, "state is required")
})
t.Run("with invalid workspace id", func(t *testing.T) {
sv, err := client.StateVersions.Create(ctx, badIdentifier, StateVersionCreateOptions{})
assert.Nil(t, sv)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestStateVersionsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
svTest, svTestCleanup := createStateVersion(t, client, 0, nil)
defer svTestCleanup()
t.Run("when the state version exists", func(t *testing.T) {
sv, err := client.StateVersions.Read(ctx, svTest.ID)
require.NoError(t, err)
// Don't compare the DownloadURL because it will be generated twice
// in this test - once at creation of the configuration version, and
// again during the GET.
svTest.DownloadURL, sv.DownloadURL = "", ""
assert.Equal(t, svTest, sv)
})
t.Run("when the state version does not exist", func(t *testing.T) {
sv, err := client.StateVersions.Read(ctx, "nonexisting")
assert.Nil(t, sv)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("with invalid state version id", func(t *testing.T) {
sv, err := client.StateVersions.Read(ctx, badIdentifier)
assert.Nil(t, sv)
assert.EqualError(t, err, "invalid value for state version ID")
})
}
func TestStateVersionsCurrent(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest1, wTest1Cleanup := createWorkspace(t, client, nil)
defer wTest1Cleanup()
wTest2, wTest2Cleanup := createWorkspace(t, client, nil)
defer wTest2Cleanup()
svTest, svTestCleanup := createStateVersion(t, client, 0, wTest1)
defer svTestCleanup()
t.Run("when a state version exists", func(t *testing.T) {
sv, err := client.StateVersions.Current(ctx, wTest1.ID)
require.NoError(t, err)
// Don't compare the DownloadURL because it will be generated twice
// in this test - once at creation of the configuration version, and
// again during the GET.
svTest.DownloadURL, sv.DownloadURL = "", ""
assert.Equal(t, svTest, sv)
})
t.Run("when a state version does not exist", func(t *testing.T) {
sv, err := client.StateVersions.Current(ctx, wTest2.ID)
assert.Nil(t, sv)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("with invalid workspace id", func(t *testing.T) {
sv, err := client.StateVersions.Current(ctx, badIdentifier)
assert.Nil(t, sv)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestStateVersionsDownload(t *testing.T) {
client := testClient(t)
ctx := context.Background()
svTest, svTestCleanup := createStateVersion(t, client, 0, nil)
defer svTestCleanup()
stateTest, err := ioutil.ReadFile("test-fixtures/state-version/terraform.tfstate")
require.NoError(t, err)
t.Run("when the state version exists", func(t *testing.T) {
state, err := client.StateVersions.Download(ctx, svTest.DownloadURL)
require.NoError(t, err)
assert.Equal(t, stateTest, state)
})
t.Run("when the state version does not exist", func(t *testing.T) {
state, err := client.StateVersions.Download(
ctx,
svTest.DownloadURL[:len(svTest.DownloadURL)-10]+"nonexisting",
)
assert.Nil(t, state)
assert.Error(t, err)
})
t.Run("with an invalid url", func(t *testing.T) {
state, err := client.StateVersions.Download(ctx, badIdentifier)
assert.Nil(t, state)
assert.Equal(t, ErrResourceNotFound, err)
})
}

214
vendor/github.com/hashicorp/go-tfe/team_access_test.go generated vendored Normal file
View File

@ -0,0 +1,214 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTeamAccessesList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
tmTest1, tmTest1Cleanup := createTeam(t, client, orgTest)
defer tmTest1Cleanup()
tmTest2, tmTest2Cleanup := createTeam(t, client, orgTest)
defer tmTest2Cleanup()
taTest1, taTest1Cleanup := createTeamAccess(t, client, tmTest1, wTest, orgTest)
defer taTest1Cleanup()
taTest2, taTest2Cleanup := createTeamAccess(t, client, tmTest2, wTest, orgTest)
defer taTest2Cleanup()
t.Run("with valid options", func(t *testing.T) {
tal, err := client.TeamAccess.List(ctx, TeamAccessListOptions{
WorkspaceID: String(wTest.ID),
})
require.NoError(t, err)
assert.Contains(t, tal.Items, taTest1)
assert.Contains(t, tal.Items, taTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, tal.CurrentPage)
assert.Equal(t, 2, tal.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
tal, err := client.TeamAccess.List(ctx, TeamAccessListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, tal.Items)
assert.Equal(t, 999, tal.CurrentPage)
assert.Equal(t, 2, tal.TotalCount)
})
t.Run("without list options", func(t *testing.T) {
tal, err := client.TeamAccess.List(ctx, TeamAccessListOptions{})
assert.Nil(t, tal)
assert.EqualError(t, err, "workspace ID is required")
})
t.Run("without a valid workspace ID", func(t *testing.T) {
tal, err := client.TeamAccess.List(ctx, TeamAccessListOptions{
WorkspaceID: String(badIdentifier),
})
assert.Nil(t, tal)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestTeamAccessesAdd(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
tmTest, tmTestCleanup := createTeam(t, client, orgTest)
defer tmTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := TeamAccessAddOptions{
Access: Access(AccessAdmin),
Team: tmTest,
Workspace: wTest,
}
ta, err := client.TeamAccess.Add(ctx, options)
require.NoError(t, err)
// Get a refreshed view from the API.
refreshed, err := client.TeamAccess.Read(ctx, ta.ID)
require.NoError(t, err)
for _, item := range []*TeamAccess{
ta,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Access, item.Access)
}
})
t.Run("when the team already has access", func(t *testing.T) {
options := TeamAccessAddOptions{
Access: Access(AccessAdmin),
Team: tmTest,
Workspace: wTest,
}
_, err := client.TeamAccess.Add(ctx, options)
assert.Error(t, err)
})
t.Run("when options is missing access", func(t *testing.T) {
ta, err := client.TeamAccess.Add(ctx, TeamAccessAddOptions{
Team: tmTest,
Workspace: wTest,
})
assert.Nil(t, ta)
assert.EqualError(t, err, "access is required")
})
t.Run("when options is missing team", func(t *testing.T) {
ta, err := client.TeamAccess.Add(ctx, TeamAccessAddOptions{
Access: Access(AccessAdmin),
Workspace: wTest,
})
assert.Nil(t, ta)
assert.EqualError(t, err, "team is required")
})
t.Run("when options is missing workspace", func(t *testing.T) {
ta, err := client.TeamAccess.Add(ctx, TeamAccessAddOptions{
Access: Access(AccessAdmin),
Team: tmTest,
})
assert.Nil(t, ta)
assert.EqualError(t, err, "workspace is required")
})
}
func TestTeamAccessesRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
taTest, taTestCleanup := createTeamAccess(t, client, nil, nil, nil)
defer taTestCleanup()
t.Run("when the team access exists", func(t *testing.T) {
ta, err := client.TeamAccess.Read(ctx, taTest.ID)
require.NoError(t, err)
assert.Equal(t, AccessAdmin, ta.Access)
t.Run("team relationship is decoded", func(t *testing.T) {
assert.NotEmpty(t, ta.Team)
})
t.Run("workspace relationship is decoded", func(t *testing.T) {
assert.NotEmpty(t, ta.Workspace)
})
})
t.Run("when the team access does not exist", func(t *testing.T) {
ta, err := client.TeamAccess.Read(ctx, "nonexisting")
assert.Nil(t, ta)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without a valid team access ID", func(t *testing.T) {
ta, err := client.TeamAccess.Read(ctx, badIdentifier)
assert.Nil(t, ta)
assert.EqualError(t, err, "invalid value for team access ID")
})
}
func TestTeamAccessesRemove(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
tmTest, tmTestCleanup := createTeam(t, client, orgTest)
defer tmTestCleanup()
taTest, _ := createTeamAccess(t, client, tmTest, nil, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.TeamAccess.Remove(ctx, taTest.ID)
require.NoError(t, err)
// Try loading the workspace - it should fail.
_, err = client.TeamAccess.Read(ctx, taTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the team access does not exist", func(t *testing.T) {
err := client.TeamAccess.Remove(ctx, taTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("when the team access ID is invalid", func(t *testing.T) {
err := client.TeamAccess.Remove(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for team access ID")
})
}

136
vendor/github.com/hashicorp/go-tfe/team_member_test.go generated vendored Normal file
View File

@ -0,0 +1,136 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTeamMembersList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
options := TeamMemberAddOptions{
Usernames: []string{"admin"},
}
err := client.TeamMembers.Add(ctx, tmTest.ID, options)
require.NoError(t, err)
t.Run("with valid options", func(t *testing.T) {
users, err := client.TeamMembers.List(ctx, tmTest.ID)
require.NoError(t, err)
require.Equal(t, 1, len(users))
found := false
for _, user := range users {
if user.Username == "admin" {
found = true
break
}
}
assert.True(t, found)
})
t.Run("when the team ID is invalid", func(t *testing.T) {
users, err := client.TeamMembers.List(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for team ID")
assert.Nil(t, users)
})
}
func TestTeamMembersAdd(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := TeamMemberAddOptions{
Usernames: []string{"admin"},
}
err := client.TeamMembers.Add(ctx, tmTest.ID, options)
require.NoError(t, err)
users, err := client.TeamMembers.List(ctx, tmTest.ID)
require.NoError(t, err)
found := false
for _, user := range users {
if user.Username == "admin" {
found = true
break
}
}
assert.True(t, found)
})
t.Run("when options is missing usernames", func(t *testing.T) {
err := client.TeamMembers.Add(ctx, tmTest.ID, TeamMemberAddOptions{})
assert.EqualError(t, err, "usernames is required")
})
t.Run("when usernames is empty", func(t *testing.T) {
err := client.TeamMembers.Add(ctx, tmTest.ID, TeamMemberAddOptions{
Usernames: []string{},
})
assert.EqualError(t, err, "invalid value for usernames")
})
t.Run("when the team ID is invalid", func(t *testing.T) {
err := client.TeamMembers.Add(ctx, badIdentifier, TeamMemberAddOptions{
Usernames: []string{"user1"},
})
assert.EqualError(t, err, "invalid value for team ID")
})
}
func TestTeamMembersRemove(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
options := TeamMemberAddOptions{
Usernames: []string{"admin"},
}
err := client.TeamMembers.Add(ctx, tmTest.ID, options)
require.NoError(t, err)
t.Run("with valid options", func(t *testing.T) {
options := TeamMemberRemoveOptions{
Usernames: []string{"admin"},
}
err := client.TeamMembers.Remove(ctx, tmTest.ID, options)
assert.NoError(t, err)
})
t.Run("when options is missing usernames", func(t *testing.T) {
err := client.TeamMembers.Remove(ctx, tmTest.ID, TeamMemberRemoveOptions{})
assert.EqualError(t, err, "usernames is required")
})
t.Run("when usernames is empty", func(t *testing.T) {
err := client.TeamMembers.Remove(ctx, tmTest.ID, TeamMemberRemoveOptions{
Usernames: []string{},
})
assert.EqualError(t, err, "invalid value for usernames")
})
t.Run("when the team ID is invalid", func(t *testing.T) {
err := client.TeamMembers.Remove(ctx, badIdentifier, TeamMemberRemoveOptions{
Usernames: []string{"user1"},
})
assert.EqualError(t, err, "invalid value for team ID")
})
}

216
vendor/github.com/hashicorp/go-tfe/team_test.go generated vendored Normal file
View File

@ -0,0 +1,216 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTeamsList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
tmTest1, tmTest1Cleanup := createTeam(t, client, orgTest)
defer tmTest1Cleanup()
tmTest2, tmTest2Cleanup := createTeam(t, client, orgTest)
defer tmTest2Cleanup()
t.Run("without list options", func(t *testing.T) {
tl, err := client.Teams.List(ctx, orgTest.Name, TeamListOptions{})
require.NoError(t, err)
assert.Contains(t, tl.Items, tmTest1)
assert.Contains(t, tl.Items, tmTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, tl.CurrentPage)
assert.Equal(t, 2, tl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
tl, err := client.Teams.List(ctx, orgTest.Name, TeamListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, tl.Items)
assert.Equal(t, 999, tl.CurrentPage)
assert.Equal(t, 2, tl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
tl, err := client.Teams.List(ctx, badIdentifier, TeamListOptions{})
assert.Nil(t, tl)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestTeamsCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := TeamCreateOptions{
Name: String("foo"),
}
tm, err := client.Teams.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
// Get a refreshed view from the API.
refreshed, err := client.Teams.Read(ctx, tm.ID)
require.NoError(t, err)
for _, item := range []*Team{
tm,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Name, item.Name)
}
})
t.Run("when options is missing name", func(t *testing.T) {
tm, err := client.Teams.Create(ctx, "foo", TeamCreateOptions{})
assert.Nil(t, tm)
assert.EqualError(t, err, "name is required")
})
t.Run("when options has an invalid organization", func(t *testing.T) {
tm, err := client.Teams.Create(ctx, badIdentifier, TeamCreateOptions{
Name: String("foo"),
})
assert.Nil(t, tm)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestTeamsRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
tmTest, tmTestCleanup := createTeam(t, client, orgTest)
defer tmTestCleanup()
t.Run("when the team exists", func(t *testing.T) {
tm, err := client.Teams.Read(ctx, tmTest.ID)
require.NoError(t, err)
assert.Equal(t, tmTest, tm)
t.Run("permissions are properly decoded", func(t *testing.T) {
assert.True(t, tm.Permissions.CanDestroy)
})
t.Run("organization access is properly decoded", func(t *testing.T) {
assert.True(t, tm.OrganizationAccess.ManagePolicies)
assert.False(t, tm.OrganizationAccess.ManageWorkspaces)
})
})
t.Run("when the team does not exist", func(t *testing.T) {
tm, err := client.Teams.Read(ctx, "nonexisting")
assert.Nil(t, tm)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without a valid team ID", func(t *testing.T) {
tm, err := client.Teams.Read(ctx, badIdentifier)
assert.Nil(t, tm)
assert.EqualError(t, err, "invalid value for team ID")
})
}
func TestTeamsUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
tmTest, tmTestCleanup := createTeam(t, client, orgTest)
defer tmTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := TeamUpdateOptions{
Name: String("foo bar"),
OrganizationAccess: &OrganizationAccessOptions{
ManagePolicies: Bool(false),
ManageVCSSettings: Bool(true)},
}
tm, err := client.Teams.Update(ctx, tmTest.ID, options)
require.NoError(t, err)
refreshed, err := client.Teams.Read(ctx, tmTest.ID)
require.NoError(t, err)
for _, item := range []*Team{
tm,
refreshed,
} {
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t,
*options.OrganizationAccess.ManagePolicies,
item.OrganizationAccess.ManagePolicies,
)
assert.Equal(t,
*options.OrganizationAccess.ManageVCSSettings,
item.OrganizationAccess.ManageVCSSettings,
)
}
})
t.Run("when the team does not exist", func(t *testing.T) {
tm, err := client.Teams.Update(ctx, "nonexisting", TeamUpdateOptions{
Name: String("foo bar"),
})
assert.Nil(t, tm)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without a valid team ID", func(t *testing.T) {
tm, err := client.Teams.Update(ctx, badIdentifier, TeamUpdateOptions{})
assert.Nil(t, tm)
assert.EqualError(t, err, "invalid value for team ID")
})
}
func TestTeamsDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
tmTest, _ := createTeam(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.Teams.Delete(ctx, tmTest.ID)
require.NoError(t, err)
// Try loading the workspace - it should fail.
_, err = client.Teams.Read(ctx, tmTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without valid team ID", func(t *testing.T) {
err := client.Teams.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for team ID")
})
}

92
vendor/github.com/hashicorp/go-tfe/team_token_test.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTeamTokensGenerate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
var tmToken string
t.Run("with valid options", func(t *testing.T) {
tt, err := client.TeamTokens.Generate(ctx, tmTest.ID)
require.NoError(t, err)
require.NotEmpty(t, tt.Token)
tmToken = tt.Token
})
t.Run("when a token already exists", func(t *testing.T) {
tt, err := client.TeamTokens.Generate(ctx, tmTest.ID)
require.NoError(t, err)
require.NotEmpty(t, tt.Token)
assert.NotEqual(t, tmToken, tt.Token)
})
t.Run("without valid team ID", func(t *testing.T) {
tt, err := client.TeamTokens.Generate(ctx, badIdentifier)
assert.Nil(t, tt)
assert.EqualError(t, err, "invalid value for team ID")
})
}
func TestTeamTokensRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
t.Run("with valid options", func(t *testing.T) {
_, ttTestCleanup := createTeamToken(t, client, tmTest)
tt, err := client.TeamTokens.Read(ctx, tmTest.ID)
assert.NoError(t, err)
assert.NotEmpty(t, tt)
ttTestCleanup()
})
t.Run("when a token doesn't exists", func(t *testing.T) {
tt, err := client.TeamTokens.Read(ctx, tmTest.ID)
assert.Equal(t, ErrResourceNotFound, err)
assert.Nil(t, tt)
})
t.Run("without valid organization", func(t *testing.T) {
tt, err := client.OrganizationTokens.Read(ctx, badIdentifier)
assert.Nil(t, tt)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestTeamTokensDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
tmTest, tmTestCleanup := createTeam(t, client, nil)
defer tmTestCleanup()
createTeamToken(t, client, tmTest)
t.Run("with valid options", func(t *testing.T) {
err := client.TeamTokens.Delete(ctx, tmTest.ID)
assert.NoError(t, err)
})
t.Run("when a token does not exist", func(t *testing.T) {
err := client.TeamTokens.Delete(ctx, tmTest.ID)
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("without valid team ID", func(t *testing.T) {
err := client.TeamTokens.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for team ID")
})
}

View File

@ -0,0 +1 @@
bar

View File

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1 @@
../foo.txt

View File

@ -0,0 +1 @@
zip

View File

@ -0,0 +1 @@
resource "null_resource" "foo" {}

View File

@ -106,6 +106,7 @@ type Client struct {
Applies Applies Applies Applies
ConfigurationVersions ConfigurationVersions ConfigurationVersions ConfigurationVersions
CostEstimations CostEstimations
NotificationConfigurations NotificationConfigurations NotificationConfigurations NotificationConfigurations
OAuthClients OAuthClients OAuthClients OAuthClients
OAuthTokens OAuthTokens OAuthTokens OAuthTokens
@ -195,6 +196,7 @@ func NewClient(cfg *Config) (*Client, error) {
// Create the services. // Create the services.
client.Applies = &applies{client: client} client.Applies = &applies{client: client}
client.ConfigurationVersions = &configurationVersions{client: client} client.ConfigurationVersions = &configurationVersions{client: client}
client.CostEstimations = &costEstimations{client: client}
client.NotificationConfigurations = &notificationConfigurations{client: client} client.NotificationConfigurations = &notificationConfigurations{client: client}
client.OAuthClients = &oAuthClients{client: client} client.OAuthClients = &oAuthClients{client: client}
client.OAuthTokens = &oAuthTokens{client: client} client.OAuthTokens = &oAuthTokens{client: client}
@ -247,7 +249,7 @@ func (c *Client) retryHTTPBackoff(min, max time.Duration, attemptNum int, resp *
} }
// Use the rate limit backoff function when we are rate limited. // Use the rate limit backoff function when we are rate limited.
if resp.StatusCode == 429 { if resp != nil && resp.StatusCode == 429 {
return rateLimitBackoff(min, max, attemptNum, resp) return rateLimitBackoff(min, max, attemptNum, resp)
} }

398
vendor/github.com/hashicorp/go-tfe/tfe_test.go generated vendored Normal file
View File

@ -0,0 +1,398 @@
package tfe
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"golang.org/x/time/rate"
)
func TestClient_newClient(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.WriteHeader(404) // We query the configured base URL which should return a 404.
}))
defer ts.Close()
cfg := &Config{
HTTPClient: ts.Client(),
}
t.Run("uses env vars if values are missing", func(t *testing.T) {
defer setupEnvVars("abcd1234", ts.URL)()
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
if client.token != "abcd1234" {
t.Fatalf("unexpected token: %q", client.token)
}
if client.baseURL.String() != ts.URL+DefaultBasePath {
t.Fatalf("unexpected address: %q", client.baseURL.String())
}
})
t.Run("fails if token is empty", func(t *testing.T) {
defer setupEnvVars("", "")()
_, err := NewClient(cfg)
if err == nil || err.Error() != "missing API token" {
t.Fatalf("unexpected error: %v", err)
}
})
t.Run("makes a new client with good settings", func(t *testing.T) {
config := &Config{
Address: ts.URL,
Token: "abcd1234",
HTTPClient: ts.Client(),
}
client, err := NewClient(config)
if err != nil {
t.Fatal(err)
}
if config.Address+DefaultBasePath != client.baseURL.String() {
t.Fatalf("unexpected client address %q", client.baseURL.String())
}
if config.Token != client.token {
t.Fatalf("unexpected client token %q", client.token)
}
if ts.Client() != client.http.HTTPClient {
t.Fatal("unexpected HTTP client value")
}
})
}
func TestClient_defaultConfig(t *testing.T) {
t.Run("with no environment variables", func(t *testing.T) {
defer setupEnvVars("", "")()
config := DefaultConfig()
if config.Address != DefaultAddress {
t.Fatalf("expected %q, got %q", DefaultAddress, config.Address)
}
if config.Token != "" {
t.Fatalf("expected empty token, got %q", config.Token)
}
if config.HTTPClient == nil {
t.Fatalf("expected default http client, got %v", config.HTTPClient)
}
})
t.Run("with environment variables", func(t *testing.T) {
defer setupEnvVars("abcd1234", "https://mytfe.local")()
})
}
func TestClient_headers(t *testing.T) {
testedCalls := 0
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
testedCalls++
if testedCalls == 1 {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.WriteHeader(404) // We query the configured base URL which should return a 404.
return
}
if r.Header.Get("Accept") != "application/vnd.api+json" {
t.Fatalf("unexpected accept header: %q", r.Header.Get("Accept"))
}
if r.Header.Get("Authorization") != "Bearer dummy-token" {
t.Fatalf("unexpected authorization header: %q", r.Header.Get("Authorization"))
}
if r.Header.Get("My-Custom-Header") != "foobar" {
t.Fatalf("unexpected custom header: %q", r.Header.Get("My-Custom-Header"))
}
if r.Header.Get("Terraform-Version") != "0.11.9" {
t.Fatalf("unexpected Terraform version header: %q", r.Header.Get("Terraform-Version"))
}
if r.Header.Get("User-Agent") != "go-tfe" {
t.Fatalf("unexpected user agent header: %q", r.Header.Get("User-Agent"))
}
}))
defer ts.Close()
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
Headers: make(http.Header),
HTTPClient: ts.Client(),
}
// Set some custom header.
cfg.Headers.Set("My-Custom-Header", "foobar")
cfg.Headers.Set("Terraform-Version", "0.11.9")
// This one should be overridden!
cfg.Headers.Set("Authorization", "bad-token")
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
// Make a few calls so we can check they all send the expected headers.
_, _ = client.Organizations.List(ctx, OrganizationListOptions{})
_, _ = client.Plans.Logs(ctx, "plan-123456789")
_ = client.Runs.Apply(ctx, "run-123456789", RunApplyOptions{})
_, _ = client.Workspaces.Lock(ctx, "ws-123456789", WorkspaceLockOptions{})
_, _ = client.Workspaces.Read(ctx, "organization", "workspace")
if testedCalls != 6 {
t.Fatalf("expected 6 tested calls, got: %d", testedCalls)
}
}
func TestClient_userAgent(t *testing.T) {
testedCalls := 0
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
testedCalls++
if testedCalls == 1 {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.WriteHeader(404) // We query the configured base URL which should return a 404.
return
}
if r.Header.Get("User-Agent") != "hashicorp" {
t.Fatalf("unexpected user agent header: %q", r.Header.Get("User-Agent"))
}
}))
defer ts.Close()
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
Headers: make(http.Header),
HTTPClient: ts.Client(),
}
// Set a custom user agent.
cfg.Headers.Set("User-Agent", "hashicorp")
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
// Make a few calls so we can check they all send the expected headers.
_, _ = client.Organizations.List(ctx, OrganizationListOptions{})
_, _ = client.Plans.Logs(ctx, "plan-123456789")
_ = client.Runs.Apply(ctx, "run-123456789", RunApplyOptions{})
_, _ = client.Workspaces.Lock(ctx, "ws-123456789", WorkspaceLockOptions{})
_, _ = client.Workspaces.Read(ctx, "organization", "workspace")
if testedCalls != 6 {
t.Fatalf("expected 6 tested calls, got: %d", testedCalls)
}
}
func TestClient_configureLimiter(t *testing.T) {
rateLimit := ""
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", rateLimit)
w.WriteHeader(404) // We query the configured base URL which should return a 404.
}))
defer ts.Close()
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
HTTPClient: ts.Client(),
}
cases := map[string]struct {
rate string
limit rate.Limit
burst int
}{
"no-value": {
rate: "",
limit: rate.Inf,
burst: 0,
},
"limit-0": {
rate: "0",
limit: rate.Inf,
burst: 0,
},
"limit-30": {
rate: "30",
limit: rate.Limit(19.8),
burst: 9,
},
"limit-100": {
rate: "100",
limit: rate.Limit(66),
burst: 33,
},
}
for name, tc := range cases {
// First set the test rate limit.
rateLimit = tc.rate
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
if client.limiter.Limit() != tc.limit {
t.Fatalf("test %s expected limit %f, got: %f", name, tc.limit, client.limiter.Limit())
}
if client.limiter.Burst() != tc.burst {
t.Fatalf("test %s expected burst %d, got: %d", name, tc.burst, client.limiter.Burst())
}
}
}
func TestClient_retryHTTPCheck(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.WriteHeader(404) // We query the configured base URL which should return a 404.
}))
defer ts.Close()
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
HTTPClient: ts.Client(),
}
connErr := errors.New("connection error")
cases := map[string]struct {
resp *http.Response
err error
retryServerErrors bool
checkOK bool
checkErr error
}{
"429-no-server-errors": {
resp: &http.Response{StatusCode: 429},
err: nil,
checkOK: true,
checkErr: nil,
},
"429-with-server-errors": {
resp: &http.Response{StatusCode: 429},
err: nil,
retryServerErrors: true,
checkOK: true,
checkErr: nil,
},
"500-no-server-errors": {
resp: &http.Response{StatusCode: 500},
err: nil,
checkOK: false,
checkErr: nil,
},
"500-with-server-errors": {
resp: &http.Response{StatusCode: 500},
err: nil,
retryServerErrors: true,
checkOK: true,
checkErr: nil,
},
"err-no-server-errors": {
err: connErr,
checkOK: false,
checkErr: connErr,
},
"err-with-server-errors": {
err: connErr,
retryServerErrors: true,
checkOK: true,
checkErr: connErr,
},
}
ctx := context.Background()
for name, tc := range cases {
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
client.RetryServerErrors(tc.retryServerErrors)
checkOK, checkErr := client.retryHTTPCheck(ctx, tc.resp, tc.err)
if checkOK != tc.checkOK {
t.Fatalf("test %s expected checkOK %t, got: %t", name, tc.checkOK, checkOK)
}
if checkErr != tc.checkErr {
t.Fatalf("test %s expected checkErr %v, got: %v", name, tc.checkErr, checkErr)
}
}
}
func TestClient_retryHTTPBackoff(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.WriteHeader(404) // We query the configured base URL which should return a 404.
}))
defer ts.Close()
var attempts int
retryLogHook := func(attemptNum int, resp *http.Response) {
attempts++
}
cfg := &Config{
Address: ts.URL,
Token: "dummy-token",
HTTPClient: ts.Client(),
RetryLogHook: retryLogHook,
}
client, err := NewClient(cfg)
if err != nil {
t.Fatal(err)
}
retries := 3
resp := &http.Response{StatusCode: 500}
for i := 0; i < retries; i++ {
client.retryHTTPBackoff(time.Second, time.Second, i, resp)
}
if attempts != retries {
t.Fatalf("expected %d log hook callbacks, got: %d callbacks", retries, attempts)
}
}
func setupEnvVars(token, address string) func() {
origToken := os.Getenv("TFE_TOKEN")
origAddress := os.Getenv("TFE_ADDRESS")
os.Setenv("TFE_TOKEN", token)
os.Setenv("TFE_ADDRESS", address)
return func() {
os.Setenv("TFE_TOKEN", origToken)
os.Setenv("TFE_ADDRESS", origAddress)
}
}

79
vendor/github.com/hashicorp/go-tfe/user_test.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUsersReadCurrent(t *testing.T) {
client := testClient(t)
ctx := context.Background()
u, err := client.Users.ReadCurrent(ctx)
assert.NoError(t, err)
assert.NotEmpty(t, u.ID)
assert.NotEmpty(t, u.AvatarURL)
assert.NotEmpty(t, u.Username)
t.Run("two factor options are decoded", func(t *testing.T) {
assert.NotNil(t, u.TwoFactor)
})
}
func TestUsersUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
uTest, err := client.Users.ReadCurrent(ctx)
require.NoError(t, err)
// Make sure we reset the current user when were done.
defer func() {
client.Users.Update(ctx, UserUpdateOptions{
Email: String(uTest.Email),
Username: String(uTest.Username),
})
}()
t.Run("without any options", func(t *testing.T) {
_, err := client.Users.Update(ctx, UserUpdateOptions{})
require.NoError(t, err)
u, err := client.Users.ReadCurrent(ctx)
assert.NoError(t, err)
assert.Equal(t, u, uTest)
})
t.Run("with a new username", func(t *testing.T) {
_, err := client.Users.Update(ctx, UserUpdateOptions{
Username: String("NewTestUsername"),
})
require.NoError(t, err)
u, err := client.Users.ReadCurrent(ctx)
assert.NoError(t, err)
assert.Equal(t, "NewTestUsername", u.Username)
})
t.Run("with a new email address", func(t *testing.T) {
_, err := client.Users.Update(ctx, UserUpdateOptions{
Email: String("newtestemail@hashicorp.com"),
})
require.NoError(t, err)
u, err := client.Users.ReadCurrent(ctx)
assert.NoError(t, err)
assert.Equal(t, "newtestemail@hashicorp.com", u.UnconfirmedEmail)
})
t.Run("with invalid email address", func(t *testing.T) {
u, err := client.Users.Update(ctx, UserUpdateOptions{
Email: String("notamailaddress"),
})
assert.Nil(t, u)
assert.Error(t, err)
})
}

295
vendor/github.com/hashicorp/go-tfe/variable_test.go generated vendored Normal file
View File

@ -0,0 +1,295 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestVariablesList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
vTest1, _ := createVariable(t, client, wTest)
vTest2, _ := createVariable(t, client, wTest)
t.Run("without list options", func(t *testing.T) {
vl, err := client.Variables.List(ctx, VariableListOptions{
Organization: String(orgTest.Name),
Workspace: String(wTest.Name),
})
require.NoError(t, err)
assert.Contains(t, vl.Items, vTest1)
assert.Contains(t, vl.Items, vTest2)
t.Skip("paging not supported yet in API")
assert.Equal(t, 1, vl.CurrentPage)
assert.Equal(t, 2, vl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
t.Skip("paging not supported yet in API")
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
vl, err := client.Variables.List(ctx, VariableListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
Organization: String(orgTest.Name),
Workspace: String(wTest.Name),
})
require.NoError(t, err)
assert.Empty(t, vl.Items)
assert.Equal(t, 999, vl.CurrentPage)
assert.Equal(t, 2, vl.TotalCount)
})
t.Run("when options is missing an organization", func(t *testing.T) {
vl, err := client.Variables.List(ctx, VariableListOptions{
Workspace: String(wTest.Name),
})
assert.Nil(t, vl)
assert.EqualError(t, err, "organization is required")
})
t.Run("when options is missing an workspace", func(t *testing.T) {
vl, err := client.Variables.List(ctx, VariableListOptions{
Organization: String(orgTest.Name),
})
assert.Nil(t, vl)
assert.EqualError(t, err, "workspace is required")
})
}
func TestVariablesCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(randomString(t)),
Value: String(randomString(t)),
Category: Category(CategoryTerraform),
Workspace: wTest,
}
v, err := client.Variables.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, v.ID)
assert.Equal(t, *options.Key, v.Key)
assert.Equal(t, *options.Value, v.Value)
assert.Equal(t, *options.Category, v.Category)
// The workspace isn't returned correcly by the API.
// assert.Equal(t, *options.Workspace, v.Workspace)
})
t.Run("when options has an empty string value", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(randomString(t)),
Value: String(""),
Category: Category(CategoryTerraform),
Workspace: wTest,
}
v, err := client.Variables.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, v.ID)
assert.Equal(t, *options.Key, v.Key)
assert.Equal(t, *options.Value, v.Value)
assert.Equal(t, *options.Category, v.Category)
})
t.Run("when options is missing value", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(randomString(t)),
Category: Category(CategoryTerraform),
Workspace: wTest,
}
v, err := client.Variables.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, v.ID)
assert.Equal(t, *options.Key, v.Key)
assert.Equal(t, "", v.Value)
assert.Equal(t, *options.Category, v.Category)
})
t.Run("when options is missing key", func(t *testing.T) {
options := VariableCreateOptions{
Value: String(randomString(t)),
Category: Category(CategoryTerraform),
Workspace: wTest,
}
_, err := client.Variables.Create(ctx, options)
assert.EqualError(t, err, "key is required")
})
t.Run("when options has an empty key", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(""),
Value: String(randomString(t)),
Category: Category(CategoryTerraform),
Workspace: wTest,
}
_, err := client.Variables.Create(ctx, options)
assert.EqualError(t, err, "key is required")
})
t.Run("when options is missing category", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(randomString(t)),
Value: String(randomString(t)),
Workspace: wTest,
}
_, err := client.Variables.Create(ctx, options)
assert.EqualError(t, err, "category is required")
})
t.Run("when options is missing workspace", func(t *testing.T) {
options := VariableCreateOptions{
Key: String(randomString(t)),
Value: String(randomString(t)),
Category: Category(CategoryTerraform),
}
_, err := client.Variables.Create(ctx, options)
assert.EqualError(t, err, "workspace is required")
})
}
func TestVariablesRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
vTest, vTestCleanup := createVariable(t, client, nil)
defer vTestCleanup()
t.Run("when the variable exists", func(t *testing.T) {
v, err := client.Variables.Read(ctx, vTest.ID)
require.NoError(t, err)
assert.Equal(t, vTest.ID, v.ID)
assert.Equal(t, vTest.Category, v.Category)
assert.Equal(t, vTest.HCL, v.HCL)
assert.Equal(t, vTest.Key, v.Key)
assert.Equal(t, vTest.Sensitive, v.Sensitive)
assert.Equal(t, vTest.Value, v.Value)
})
t.Run("when the variable does not exist", func(t *testing.T) {
v, err := client.Variables.Read(ctx, "nonexisting")
assert.Nil(t, v)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("without a valid variable ID", func(t *testing.T) {
v, err := client.Variables.Read(ctx, badIdentifier)
assert.Nil(t, v)
assert.EqualError(t, err, "invalid value for variable ID")
})
}
func TestVariablesUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
vTest, vTestCleanup := createVariable(t, client, nil)
defer vTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := VariableUpdateOptions{
Key: String("newname"),
Value: String("newvalue"),
HCL: Bool(true),
}
v, err := client.Variables.Update(ctx, vTest.ID, options)
require.NoError(t, err)
assert.Equal(t, *options.Key, v.Key)
assert.Equal(t, *options.HCL, v.HCL)
assert.Equal(t, *options.Value, v.Value)
})
t.Run("when updating a subset of values", func(t *testing.T) {
options := VariableUpdateOptions{
Key: String("someothername"),
HCL: Bool(false),
}
v, err := client.Variables.Update(ctx, vTest.ID, options)
require.NoError(t, err)
assert.Equal(t, *options.Key, v.Key)
assert.Equal(t, *options.HCL, v.HCL)
})
t.Run("with sensitive set", func(t *testing.T) {
options := VariableUpdateOptions{
Sensitive: Bool(true),
}
v, err := client.Variables.Update(ctx, vTest.ID, options)
require.NoError(t, err)
assert.Equal(t, *options.Sensitive, v.Sensitive)
assert.Empty(t, v.Value) // Because its now sensitive
})
t.Run("without any changes", func(t *testing.T) {
vTest, vTestCleanup := createVariable(t, client, nil)
defer vTestCleanup()
v, err := client.Variables.Update(ctx, vTest.ID, VariableUpdateOptions{})
require.NoError(t, err)
assert.Equal(t, vTest, v)
})
t.Run("with invalid variable ID", func(t *testing.T) {
_, err := client.Variables.Update(ctx, badIdentifier, VariableUpdateOptions{})
assert.EqualError(t, err, "invalid value for variable ID")
})
}
func TestVariablesDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
wTest, wTestCleanup := createWorkspace(t, client, nil)
defer wTestCleanup()
vTest, _ := createVariable(t, client, wTest)
t.Run("with valid options", func(t *testing.T) {
err := client.Variables.Delete(ctx, vTest.ID)
assert.NoError(t, err)
})
t.Run("with non existing variable ID", func(t *testing.T) {
err := client.Variables.Delete(ctx, "nonexisting")
assert.Equal(t, err, ErrResourceNotFound)
})
t.Run("with invalid variable ID", func(t *testing.T) {
err := client.Variables.Delete(ctx, badIdentifier)
assert.EqualError(t, err, "invalid value for variable ID")
})
}

496
vendor/github.com/hashicorp/go-tfe/workspace_test.go generated vendored Normal file
View File

@ -0,0 +1,496 @@
package tfe
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWorkspacesList(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest1, wTest1Cleanup := createWorkspace(t, client, orgTest)
defer wTest1Cleanup()
wTest2, wTest2Cleanup := createWorkspace(t, client, orgTest)
defer wTest2Cleanup()
t.Run("without list options", func(t *testing.T) {
wl, err := client.Workspaces.List(ctx, orgTest.Name, WorkspaceListOptions{})
require.NoError(t, err)
assert.Contains(t, wl.Items, wTest1)
assert.Contains(t, wl.Items, wTest2)
assert.Equal(t, 1, wl.CurrentPage)
assert.Equal(t, 2, wl.TotalCount)
})
t.Run("with list options", func(t *testing.T) {
// Request a page number which is out of range. The result should
// be successful, but return no results if the paging options are
// properly passed along.
wl, err := client.Workspaces.List(ctx, orgTest.Name, WorkspaceListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
})
require.NoError(t, err)
assert.Empty(t, wl.Items)
assert.Equal(t, 999, wl.CurrentPage)
assert.Equal(t, 2, wl.TotalCount)
})
t.Run("when searching a known workspace", func(t *testing.T) {
// Use a known workspace prefix as search attribute. The result
// should be successful and only contain the matching workspace.
wl, err := client.Workspaces.List(ctx, orgTest.Name, WorkspaceListOptions{
Search: String(wTest1.Name[:len(wTest1.Name)-5]),
})
require.NoError(t, err)
assert.Contains(t, wl.Items, wTest1)
assert.NotContains(t, wl.Items, wTest2)
assert.Equal(t, 1, wl.CurrentPage)
assert.Equal(t, 1, wl.TotalCount)
})
t.Run("when searching an unknown workspace", func(t *testing.T) {
// Use a nonexisting workspace name as search attribute. The result
// should be successful, but return no results.
wl, err := client.Workspaces.List(ctx, orgTest.Name, WorkspaceListOptions{
Search: String("nonexisting"),
})
require.NoError(t, err)
assert.Empty(t, wl.Items)
assert.Equal(t, 1, wl.CurrentPage)
assert.Equal(t, 0, wl.TotalCount)
})
t.Run("without a valid organization", func(t *testing.T) {
wl, err := client.Workspaces.List(ctx, badIdentifier, WorkspaceListOptions{})
assert.Nil(t, wl)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestWorkspacesCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
t.Run("with valid options", func(t *testing.T) {
options := WorkspaceCreateOptions{
Name: String("foo"),
AutoApply: Bool(true),
QueueAllRuns: Bool(true),
TerraformVersion: String("0.11.0"),
WorkingDirectory: String("bar/"),
}
w, err := client.Workspaces.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
// Get a refreshed view from the API.
refreshed, err := client.Workspaces.Read(ctx, orgTest.Name, *options.Name)
require.NoError(t, err)
for _, item := range []*Workspace{
w,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t, *options.AutoApply, item.AutoApply)
assert.Equal(t, *options.QueueAllRuns, item.QueueAllRuns)
assert.Equal(t, *options.TerraformVersion, item.TerraformVersion)
assert.Equal(t, *options.WorkingDirectory, item.WorkingDirectory)
}
})
t.Run("when options is missing name", func(t *testing.T) {
w, err := client.Workspaces.Create(ctx, "foo", WorkspaceCreateOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "name is required")
})
t.Run("when options has an invalid name", func(t *testing.T) {
w, err := client.Workspaces.Create(ctx, "foo", WorkspaceCreateOptions{
Name: String(badIdentifier),
})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for name")
})
t.Run("when options has an invalid organization", func(t *testing.T) {
w, err := client.Workspaces.Create(ctx, badIdentifier, WorkspaceCreateOptions{
Name: String("foo"),
})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when an error is returned from the api", func(t *testing.T) {
w, err := client.Workspaces.Create(ctx, "bar", WorkspaceCreateOptions{
Name: String("bar"),
TerraformVersion: String("nonexisting"),
})
assert.Nil(t, w)
assert.Error(t, err)
})
}
func TestWorkspacesRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, wTestCleanup := createWorkspace(t, client, orgTest)
defer wTestCleanup()
t.Run("when the workspace exists", func(t *testing.T) {
w, err := client.Workspaces.Read(ctx, orgTest.Name, wTest.Name)
require.NoError(t, err)
assert.Equal(t, wTest, w)
t.Run("permissions are properly decoded", func(t *testing.T) {
assert.True(t, w.Permissions.CanDestroy)
})
t.Run("relationships are properly decoded", func(t *testing.T) {
assert.Equal(t, orgTest.Name, w.Organization.Name)
})
t.Run("timestamps are properly decoded", func(t *testing.T) {
assert.NotEmpty(t, w.CreatedAt)
})
})
t.Run("when the workspace does not exist", func(t *testing.T) {
w, err := client.Workspaces.Read(ctx, orgTest.Name, "nonexisting")
assert.Nil(t, w)
assert.Error(t, err)
})
t.Run("when the organization does not exist", func(t *testing.T) {
w, err := client.Workspaces.Read(ctx, "nonexisting", "nonexisting")
assert.Nil(t, w)
assert.Error(t, err)
})
t.Run("without a valid organization", func(t *testing.T) {
w, err := client.Workspaces.Read(ctx, badIdentifier, wTest.Name)
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("without a valid workspace", func(t *testing.T) {
w, err := client.Workspaces.Read(ctx, orgTest.Name, badIdentifier)
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace")
})
}
func TestWorkspacesUpdate(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
t.Run("when updating a subset of values", func(t *testing.T) {
options := WorkspaceUpdateOptions{
Name: String(wTest.Name),
AutoApply: Bool(true),
QueueAllRuns: Bool(true),
TerraformVersion: String("0.10.0"),
}
wAfter, err := client.Workspaces.Update(ctx, orgTest.Name, wTest.Name, options)
require.NoError(t, err)
assert.Equal(t, wTest.Name, wAfter.Name)
assert.NotEqual(t, wTest.AutoApply, wAfter.AutoApply)
assert.NotEqual(t, wTest.QueueAllRuns, wAfter.QueueAllRuns)
assert.NotEqual(t, wTest.TerraformVersion, wAfter.TerraformVersion)
assert.Equal(t, wTest.WorkingDirectory, wAfter.WorkingDirectory)
})
t.Run("with valid options", func(t *testing.T) {
options := WorkspaceUpdateOptions{
Name: String(randomString(t)),
AutoApply: Bool(false),
QueueAllRuns: Bool(false),
TerraformVersion: String("0.11.1"),
WorkingDirectory: String("baz/"),
}
w, err := client.Workspaces.Update(ctx, orgTest.Name, wTest.Name, options)
require.NoError(t, err)
// Get a refreshed view of the workspace from the API
refreshed, err := client.Workspaces.Read(ctx, orgTest.Name, *options.Name)
require.NoError(t, err)
for _, item := range []*Workspace{
w,
refreshed,
} {
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t, *options.AutoApply, item.AutoApply)
assert.Equal(t, *options.QueueAllRuns, item.QueueAllRuns)
assert.Equal(t, *options.TerraformVersion, item.TerraformVersion)
assert.Equal(t, *options.WorkingDirectory, item.WorkingDirectory)
}
})
t.Run("when an error is returned from the api", func(t *testing.T) {
w, err := client.Workspaces.Update(ctx, orgTest.Name, wTest.Name, WorkspaceUpdateOptions{
TerraformVersion: String("nonexisting"),
})
assert.Nil(t, w)
assert.Error(t, err)
})
t.Run("when options has an invalid name", func(t *testing.T) {
w, err := client.Workspaces.Update(ctx, orgTest.Name, badIdentifier, WorkspaceUpdateOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace")
})
t.Run("when options has an invalid organization", func(t *testing.T) {
w, err := client.Workspaces.Update(ctx, badIdentifier, wTest.Name, WorkspaceUpdateOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for organization")
})
}
func TestWorkspacesDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
err := client.Workspaces.Delete(ctx, orgTest.Name, wTest.Name)
require.NoError(t, err)
// Try loading the workspace - it should fail.
_, err = client.Workspaces.Read(ctx, orgTest.Name, wTest.Name)
assert.Equal(t, ErrResourceNotFound, err)
})
t.Run("when organization is invalid", func(t *testing.T) {
err := client.Workspaces.Delete(ctx, badIdentifier, wTest.Name)
assert.EqualError(t, err, "invalid value for organization")
})
t.Run("when workspace is invalid", func(t *testing.T) {
err := client.Workspaces.Delete(ctx, orgTest.Name, badIdentifier)
assert.EqualError(t, err, "invalid value for workspace")
})
}
func TestWorkspacesRemoveVCSConnection(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspaceWithVCS(t, client, orgTest)
t.Run("remove vcs integration", func(t *testing.T) {
w, err := client.Workspaces.RemoveVCSConnection(ctx, orgTest.Name, wTest.Name)
require.NoError(t, err)
assert.Equal(t, (*VCSRepo)(nil), w.VCSRepo)
})
}
func TestWorkspacesLock(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
t.Run("with valid options", func(t *testing.T) {
w, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
require.NoError(t, err)
assert.True(t, w.Locked)
})
t.Run("when workspace is already locked", func(t *testing.T) {
_, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
assert.Equal(t, ErrWorkspaceLocked, err)
})
t.Run("without a valid workspace ID", func(t *testing.T) {
w, err := client.Workspaces.Lock(ctx, badIdentifier, WorkspaceLockOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestWorkspacesUnlock(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
w, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
if err != nil {
orgTestCleanup()
}
require.NoError(t, err)
require.True(t, w.Locked)
t.Run("with valid options", func(t *testing.T) {
w, err := client.Workspaces.Unlock(ctx, wTest.ID)
require.NoError(t, err)
assert.False(t, w.Locked)
})
t.Run("when workspace is already unlocked", func(t *testing.T) {
_, err := client.Workspaces.Unlock(ctx, wTest.ID)
assert.Equal(t, ErrWorkspaceNotLocked, err)
})
t.Run("without a valid workspace ID", func(t *testing.T) {
w, err := client.Workspaces.Unlock(ctx, badIdentifier)
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestWorkspacesForceUnlock(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, _ := createWorkspace(t, client, orgTest)
w, err := client.Workspaces.Lock(ctx, wTest.ID, WorkspaceLockOptions{})
if err != nil {
orgTestCleanup()
}
require.NoError(t, err)
require.True(t, w.Locked)
t.Run("with valid options", func(t *testing.T) {
w, err := client.Workspaces.ForceUnlock(ctx, wTest.ID)
require.NoError(t, err)
assert.False(t, w.Locked)
})
t.Run("when workspace is already unlocked", func(t *testing.T) {
_, err := client.Workspaces.ForceUnlock(ctx, wTest.ID)
assert.Equal(t, ErrWorkspaceNotLocked, err)
})
t.Run("without a valid workspace ID", func(t *testing.T) {
w, err := client.Workspaces.ForceUnlock(ctx, badIdentifier)
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestWorkspacesAssignSSHKey(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, wTestCleanup := createWorkspace(t, client, orgTest)
defer wTestCleanup()
sshKeyTest, sshKeyTestCleanup := createSSHKey(t, client, orgTest)
defer sshKeyTestCleanup()
t.Run("with valid options", func(t *testing.T) {
w, err := client.Workspaces.AssignSSHKey(ctx, wTest.ID, WorkspaceAssignSSHKeyOptions{
SSHKeyID: String(sshKeyTest.ID),
})
require.NoError(t, err)
require.NotNil(t, w.SSHKey)
assert.Equal(t, w.SSHKey.ID, sshKeyTest.ID)
})
t.Run("without an SSH key ID", func(t *testing.T) {
w, err := client.Workspaces.AssignSSHKey(ctx, wTest.ID, WorkspaceAssignSSHKeyOptions{})
assert.Nil(t, w)
assert.EqualError(t, err, "SSH key ID is required")
})
t.Run("without a valid SSH key ID", func(t *testing.T) {
w, err := client.Workspaces.AssignSSHKey(ctx, wTest.ID, WorkspaceAssignSSHKeyOptions{
SSHKeyID: String(badIdentifier),
})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for SSH key ID")
})
t.Run("without a valid workspace ID", func(t *testing.T) {
w, err := client.Workspaces.AssignSSHKey(ctx, badIdentifier, WorkspaceAssignSSHKeyOptions{
SSHKeyID: String(sshKeyTest.ID),
})
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}
func TestWorkspacesUnassignSSHKey(t *testing.T) {
client := testClient(t)
ctx := context.Background()
orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()
wTest, wTestCleanup := createWorkspace(t, client, orgTest)
defer wTestCleanup()
sshKeyTest, sshKeyTestCleanup := createSSHKey(t, client, orgTest)
defer sshKeyTestCleanup()
w, err := client.Workspaces.AssignSSHKey(ctx, wTest.ID, WorkspaceAssignSSHKeyOptions{
SSHKeyID: String(sshKeyTest.ID),
})
if err != nil {
orgTestCleanup()
}
require.NoError(t, err)
require.NotNil(t, w.SSHKey)
require.Equal(t, w.SSHKey.ID, sshKeyTest.ID)
t.Run("with valid options", func(t *testing.T) {
w, err := client.Workspaces.UnassignSSHKey(ctx, wTest.ID)
assert.Nil(t, err)
assert.Nil(t, w.SSHKey)
})
t.Run("without a valid workspace ID", func(t *testing.T) {
w, err := client.Workspaces.UnassignSSHKey(ctx, badIdentifier)
assert.Nil(t, w)
assert.EqualError(t, err, "invalid value for workspace ID")
})
}