Skip to content

Commit

Permalink
StateVersionOutputs (#246)
Browse files Browse the repository at this point in the history
* Add interface to value
* use latest hashicorp/jsonapi
* Fix failed tests
  • Loading branch information
omarismail authored Aug 20, 2021
1 parent 0d658f2 commit b8f3feb
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 15 deletions.
3 changes: 2 additions & 1 deletion configuration_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ func TestConfigurationVersionsCreate(t *testing.T) {
wTest.ID,
ConfigurationVersionCreateOptions{},
)
assert.NotEmpty(t, cv.UploadURL)
require.NoError(t, err)

// Get a refreshed view of the configuration version.
refreshed, err := client.ConfigurationVersions.Read(ctx, cv.ID)
require.NoError(t, err)
assert.Empty(t, refreshed.UploadURL)

for _, item := range []*ConfigurationVersion{
cv,
Expand All @@ -97,7 +99,6 @@ func TestConfigurationVersionsCreate(t *testing.T) {
assert.Empty(t, item.Error)
assert.Equal(t, item.Source, ConfigurationSourceAPI)
assert.Equal(t, item.Status, ConfigurationPending)
assert.NotEmpty(t, item.UploadURL)
}
})

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.5.2
github.com/hashicorp/go-slug v0.7.0
github.com/hashicorp/go-uuid v1.0.1
github.com/hashicorp/jsonapi v0.0.0-20210518035559-1e50d74c8db3
github.com/hashicorp/jsonapi v0.0.0-20210817203359-15d518142555
github.com/stretchr/testify v1.3.0
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
)
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6K
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4=
github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc=
github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8=
github.com/hashicorp/go-slug v0.7.0 h1:8HIi6oreWPtnhpYd8lIGQBgp4rXzDWQTOhfILZm+nok=
github.com/hashicorp/go-slug v0.7.0/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/jsonapi v0.0.0-20210518035559-1e50d74c8db3 h1:mzwkutymYIXR5oQT9YnfbLuuw7LZmksiHKRPUTN5ijo=
github.com/hashicorp/jsonapi v0.0.0-20210518035559-1e50d74c8db3/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik=
github.com/hashicorp/jsonapi v0.0.0-20210817203359-15d518142555 h1:uKQ7kOVDmshUT7uoFYn8MDWXUmTOBqqmQkRS0sdQaaA=
github.com/hashicorp/jsonapi v0.0.0-20210817203359-15d518142555/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
9 changes: 8 additions & 1 deletion policy_set_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package tfe
import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const waitForPolicySetVersionUpload = 500 * time.Millisecond

func TestPolicySetVersionsCreate(t *testing.T) {
skipIfFreeOnly(t)

Expand Down Expand Up @@ -79,9 +82,13 @@ func TestPolicySetVersionsUpload(t *testing.T) {
)
require.NoError(t, err)

// give TFC soe time to process uploading the
// policy set version before reaeding..
time.Sleep(waitForPolicySetVersionUpload)

psv, err = client.PolicySetVersions.Read(ctx, psv.ID)
require.NoError(t, err)
assert.Equal(t, psv.Status, PolicySetVersionReady)
assert.Equal(t, PolicySetVersionReady, psv.Status)
})

t.Run("with missing upload URL", func(t *testing.T) {
Expand Down
36 changes: 36 additions & 0 deletions state_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type StateVersions interface {

// Download retrieves the actual stored state of a state version
Download(ctx context.Context, url string) ([]byte, error)

// Outputs retrieves all the outputs of a state version by its ID.
Outputs(ctx context.Context, svID string, options StateVersionOutputsListOptions) ([]*StateVersionOutput, error)
}

// stateVersions implements StateVersions.
Expand Down Expand Up @@ -245,3 +248,36 @@ func (s *stateVersions) Download(ctx context.Context, url string) ([]byte, error

return buf.Bytes(), nil
}

// StateVersionOutputsList represents a list of StateVersionOutput items.
type StateVersionOutputsList struct {
*Pagination
Items []*StateVersionOutput
}

// StateVersionOutputsListOptions represents the options for listing state
// version outputs.
type StateVersionOutputsListOptions struct {
ListOptions
}

// Outputs retrieves all the outputs of a state version by its ID.
func (s *stateVersions) Outputs(ctx context.Context, svID string, options StateVersionOutputsListOptions) ([]*StateVersionOutput, error) {
if !validStringID(&svID) {
return nil, errors.New("invalid value for state version ID")
}

u := fmt.Sprintf("state-versions/%s/outputs", url.QueryEscape(svID))
req, err := s.client.newRequest("GET", u, options)
if err != nil {
return nil, err
}

sv := &StateVersionOutputsList{}
err = s.client.do(ctx, req, sv)
if err != nil {
return nil, err
}

return sv.Items, nil
}
10 changes: 5 additions & 5 deletions state_version_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ type stateVersionOutputs struct {
}

type StateVersionOutput struct {
ID string `jsonapi:"primary,state-version-outputs"`
Name string `jsonapi:"attr,name"`
Sensitive bool `jsonapi:"attr,sensitive"`
Type string `jsonapi:"attr,type"`
Value string `jsonapi:"attr,value"`
ID string `jsonapi:"primary,state-version-outputs"`
Name string `jsonapi:"attr,name"`
Sensitive bool `jsonapi:"attr,sensitive"`
Type string `jsonapi:"attr,type"`
Value interface{} `jsonapi:"attr,value"`
}

func (s *stateVersionOutputs) Read(ctx context.Context, outputID string) (*StateVersionOutput, error) {
Expand Down
55 changes: 55 additions & 0 deletions state_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,58 @@ func TestStateVersionsDownload(t *testing.T) {
assert.Equal(t, ErrResourceNotFound, err)
})
}

func TestStateVersionOutputs(t *testing.T) {
client := testClient(t)
ctx := context.Background()

wTest1, wTest1Cleanup := createWorkspace(t, client, nil)
defer wTest1Cleanup()

sv, svTestCleanup := createStateVersion(t, client, 0, wTest1)
defer svTestCleanup()

// give TFC some time to process the statefile and extract the outputs.
time.Sleep(waitForStateVersionOutputs)

t.Run("when the state version exists", func(t *testing.T) {
outputs, err := client.StateVersions.Outputs(ctx, sv.ID, StateVersionOutputsListOptions{})
require.NoError(t, err)

assert.NotEmpty(t, outputs)

values := map[string]interface{}{}
for _, op := range outputs {
values[op.Name] = op.Value
}

// These asserts are based off of the values in
// test-fixtures/state-version/terraform.tfstate
assert.Equal(t, "9023256633839603543", values["test_output_string"].(string))
assert.Equal(t, float64(5), values["test_output_number"].(float64))
assert.Equal(t, true, values["test_output_bool"].(bool))
assert.Equal(t, []interface{}{"us-west-1a"}, values["test_output_list_string"].([]interface{}))
assert.Equal(t, []interface{}{float64(1), float64(2)}, values["test_output_tuple_number"].([]interface{}))
assert.Equal(t, []interface{}{"one", "two"}, values["test_output_tuple_string"].([]interface{}))
assert.Equal(t, map[string]interface{}{"foo": "bar"}, values["test_output_object"].(map[string]interface{}))
})

t.Run("with list options", func(t *testing.T) {
options := StateVersionOutputsListOptions{
ListOptions: ListOptions{
PageNumber: 999,
PageSize: 100,
},
}
outputs, err := client.StateVersions.Outputs(ctx, sv.ID, options)
require.NoError(t, err)
assert.Empty(t, outputs)
})

t.Run("when the state version does not exist", func(t *testing.T) {
outputs, err := client.StateVersions.Outputs(ctx, "sv-999999999", StateVersionOutputsListOptions{})
assert.Nil(t, outputs)
assert.Error(t, err)
})

}
56 changes: 55 additions & 1 deletion test-fixtures/state-version/terraform.tfstate
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,63 @@
"serial": 2,
"lineage": "b2b54b23-e7ea-5500-7b15-fcb68c1d92bb",
"outputs": {
"test_output": {
"test_output_list_string": {
"value": [
"us-west-1a"
],
"type": [
"list",
"string"
]
},
"test_output_string": {
"value": "9023256633839603543",
"type": "string"
},
"test_output_tuple_number": {
"value": [
1,
2
],
"type": [
"tuple",
[
"number",
"number"
]
]
},
"test_output_tuple_string": {
"value": [
"one",
"two"
],
"type": [
"tuple",
[
"string",
"string"
]
]
},
"test_output_object": {
"value": {
"foo": "bar"
},
"type": [
"object",
{
"foo": "string"
}
]
},
"test_output_number": {
"value": 5,
"type": "number"
},
"test_output_bool": {
"value": true,
"type": "bool"
}
},
"resources": [
Expand Down
2 changes: 1 addition & 1 deletion tfe.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ func unmarshalResponse(responseBody io.Reader, model interface{}) error {

// Return an error if model is not a struct or an io.Writer.
if dst.Kind() != reflect.Struct {
return fmt.Errorf("v must be a struct or an io.Writer")
return fmt.Errorf("%v must be a struct or an io.Writer", dst)
}

// Try to get the Items and Pagination struct fields.
Expand Down
3 changes: 2 additions & 1 deletion tfe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
Expand Down Expand Up @@ -477,7 +478,7 @@ func Test_unmarshalResponse(t *testing.T) {
notStruct := "not a struct"
err := unmarshalResponse(responseBody, notStruct)
assert.Error(t, err)
assert.EqualError(t, err, "v must be a struct or an io.Writer")
assert.EqualError(t, err, fmt.Sprintf("%v must be a struct or an io.Writer", notStruct))
})

}
Expand Down

0 comments on commit b8f3feb

Please sign in to comment.