Skip to content

Commit

Permalink
Add team API key tests
Browse files Browse the repository at this point in the history
  • Loading branch information
michal-futurice committed Jul 25, 2024
1 parent 4779b8d commit 2b33a1c
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 18 deletions.
12 changes: 7 additions & 5 deletions internal/provider/teamapikey/team_api_key_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ package teamapikey
import (
"context"
"fmt"
"github.com/futurice/terraform-provider-dependencytrack/internal/utils"
"strings"

dtrack "github.com/futurice/dependency-track-client-go"
"github.com/google/uuid"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand Down Expand Up @@ -86,12 +85,17 @@ func (r *TeamAPIKeyResource) Create(ctx context.Context, req resource.CreateRequ
var plan TeamAPIKeyResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

teamUUID, teamUUIDDiags := utils.ParseUUID(plan.TeamID.ValueString())
resp.Diagnostics.Append(teamUUIDDiags...)
if resp.Diagnostics.HasError() {
return
}

apiKey, err := r.client.Team.GenerateAPIKey(ctx, uuid.MustParse(plan.TeamID.String()))
apiKey, err := r.client.Team.GenerateAPIKey(ctx, teamUUID)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create API key, got error: %s", err))
return
Expand All @@ -106,7 +110,6 @@ func (r *TeamAPIKeyResource) Read(ctx context.Context, req resource.ReadRequest,
var state TeamAPIKeyResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)

if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -148,7 +151,6 @@ func (r *TeamAPIKeyResource) Delete(ctx context.Context, req resource.DeleteRequ
var state TeamAPIKeyResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)

if resp.Diagnostics.HasError() {
return
}
Expand Down
145 changes: 145 additions & 0 deletions internal/provider/teamapikey/team_api_key_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package teamapikey_test

import (
"fmt"
"github.com/futurice/terraform-provider-dependencytrack/internal/testutils"
"github.com/futurice/terraform-provider-dependencytrack/internal/testutils/teamtestutils"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"os"
"testing"
)

var testDependencyTrack *testutils.TestDependencyTrack

func TestMain(m *testing.M) {
if os.Getenv(resource.EnvTfAcc) != "" {
var cleanup func()
testDependencyTrack, cleanup = testutils.InitTestDependencyTrack()
defer cleanup()
}

m.Run()
}

func TestAccTeamResource_basic(t *testing.T) {
ctx := testutils.CreateTestContext(t)

teamName := acctest.RandomWithPrefix("test-team")

teamResourceName := teamtestutils.CreateTeamResourceName("test")
otherTeamResourceName := teamtestutils.CreateTeamResourceName("test-other")
apiKeyResourceName := teamtestutils.CreateTeamAPIKeyResourceName("test")

var teamID, otherTeamID, teamAPIKey, otherTeamAPIKey string

resource.Test(t, resource.TestCase{
PreCheck: func() { testutils.TestAccPreCheck(t) },
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccTeamAPIKeyConfigBasic(testDependencyTrack, teamName),
Check: resource.ComposeAggregateTestCheckFunc(
teamtestutils.TestAccCheckGetTeamSingleAPIKey(ctx, testDependencyTrack, teamResourceName, &teamAPIKey),
testutils.TestAccCheckGetResourceID(teamResourceName, &teamID),
resource.TestCheckResourceAttrPtr(apiKeyResourceName, "team_id", &teamID),
resource.TestCheckResourceAttrPtr(apiKeyResourceName, "value", &teamAPIKey),
),
},
{
ResourceName: apiKeyResourceName,
ImportStateIdFunc: func(state *terraform.State) (string, error) {
return fmt.Sprintf("%s/%s", teamID, teamAPIKey), nil
},
ImportState: true,
// Unable to verify since the resource has no ID and no non-sensitive ID can be synthesised; we are just smoke-testing the import
ImportStateVerify: false,
},
{
Config: testAccTeamAPIKeyConfigOtherTeam(testDependencyTrack, teamName),
Check: resource.ComposeAggregateTestCheckFunc(
teamtestutils.TestAccCheckTeamHasNoAPIKeys(ctx, testDependencyTrack, teamResourceName),
teamtestutils.TestAccCheckGetTeamSingleAPIKey(ctx, testDependencyTrack, otherTeamResourceName, &otherTeamAPIKey),
testutils.TestAccCheckGetResourceID(otherTeamResourceName, &otherTeamID),
resource.TestCheckResourceAttrPtr(apiKeyResourceName, "team_id", &otherTeamID),
resource.TestCheckResourceAttrPtr(apiKeyResourceName, "value", &otherTeamAPIKey),
),
},
{
Config: testAccTeamPermissionConfigNoAPIKey(testDependencyTrack, teamName),
Check: resource.ComposeAggregateTestCheckFunc(
teamtestutils.TestAccCheckTeamHasNoAPIKeys(ctx, testDependencyTrack, teamResourceName),
teamtestutils.TestAccCheckTeamHasNoAPIKeys(ctx, testDependencyTrack, otherTeamResourceName),
),
},
},
// CheckDestroy is not practical here since the team is destroyed as well, and we can no longer query its permissions
})
}

func testAccTeamAPIKeyConfigBasic(testDependencyTrack *testutils.TestDependencyTrack, teamName string) string {
return testDependencyTrack.AddProviderConfiguration(
testutils.ComposeConfigs(
fmt.Sprintf(`
resource "dependencytrack_team" "test" {
name = %[1]q
}
`,
teamName,
),
`
resource "dependencytrack_team_api_key" "test" {
team_id = dependencytrack_team.test.id
}
`,
),
)
}

func testAccTeamAPIKeyConfigOtherTeam(testDependencyTrack *testutils.TestDependencyTrack, teamName string) string {
return testDependencyTrack.AddProviderConfiguration(
testutils.ComposeConfigs(
fmt.Sprintf(`
resource "dependencytrack_team" "test" {
name = %[1]q
}
`,
teamName,
),
fmt.Sprintf(`
resource "dependencytrack_team" "test-other" {
name = "%[1]s-other"
}
`,
teamName,
),
`
resource "dependencytrack_team_api_key" "test" {
team_id = dependencytrack_team.test-other.id
}
`,
),
)
}

func testAccTeamPermissionConfigNoAPIKey(testDependencyTrack *testutils.TestDependencyTrack, teamName string) string {
return testDependencyTrack.AddProviderConfiguration(
testutils.ComposeConfigs(
fmt.Sprintf(`
resource "dependencytrack_team" "test" {
name = %[1]q
}
`,
teamName,
),
fmt.Sprintf(`
resource "dependencytrack_team" "test-other" {
name = "%[1]s-other"
}
`,
teamName,
),
),
)
}
75 changes: 62 additions & 13 deletions internal/testutils/teamtestutils/teamtestutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package teamtestutils

import (
"context"
"errors"
"fmt"
dtrack "github.com/futurice/dependency-track-client-go"
"github.com/futurice/terraform-provider-dependencytrack/internal/testutils"
Expand Down Expand Up @@ -82,6 +81,44 @@ func TestAccCheckTeamHasExpectedPermissions(ctx context.Context, testDependencyT
}
}

func TestAccCheckTeamHasNoAPIKeys(ctx context.Context, testDependencyTrack *testutils.TestDependencyTrack, resourceName string) resource.TestCheckFunc {
return func(state *terraform.State) error {
team, err := FindTeamByResourceName(ctx, testDependencyTrack, state, resourceName)
if err != nil {
return err
}
if team == nil {
return fmt.Errorf("team for resource %s does not exist in Dependency-Track", resourceName)
}

if len(team.APIKeys) != 0 {
return fmt.Errorf("team for resource %s has %d API keys instead of the expected 0", resourceName, len(team.APIKeys))
}

return nil
}
}

func TestAccCheckGetTeamSingleAPIKey(ctx context.Context, testDependencyTrack *testutils.TestDependencyTrack, resourceName string, apiKeyTarget *string) resource.TestCheckFunc {
return func(state *terraform.State) error {
team, err := FindTeamByResourceName(ctx, testDependencyTrack, state, resourceName)
if err != nil {
return err
}
if team == nil {
return fmt.Errorf("team for resource %s does not exist in Dependency-Track", resourceName)
}

if len(team.APIKeys) != 1 {
return fmt.Errorf("team for resource %s has %d API keys instead of the expected 1", resourceName, len(team.APIKeys))
}

*apiKeyTarget = team.APIKeys[0].Key

return nil
}
}

func FindTeamByResourceName(ctx context.Context, testDependencyTrack *testutils.TestDependencyTrack, state *terraform.State, resourceName string) (*dtrack.Team, error) {
teamID, err := testutils.GetResourceID(state, resourceName)
if err != nil {
Expand All @@ -97,23 +134,31 @@ func FindTeamByResourceName(ctx context.Context, testDependencyTrack *testutils.
}

func FindTeam(ctx context.Context, testDependencyTrack *testutils.TestDependencyTrack, teamID uuid.UUID) (*dtrack.Team, error) {
team, err := testDependencyTrack.Client.Team.Get(ctx, teamID)
// Currently the endpoint for getting one team does not return most of the data
// see https://github.com/DependencyTrack/dependency-track/issues/4000
teams, err := testDependencyTrack.Client.Team.GetAll(ctx, dtrack.PageOptions{})
if err != nil {
var apiErr *dtrack.APIError
ok := errors.As(err, &apiErr)
if !ok || apiErr.StatusCode != 404 {
return nil, fmt.Errorf("failed to get team from Dependency-Track: %w", err)
}

return nil, nil
return nil, fmt.Errorf("failed to get teams from Dependency-Track: %w", err)
}

// normalize the returned object not to contain an empty array reference
if len(team.Permissions) == 0 {
team.Permissions = nil
for _, team := range teams.Items {
if team.UUID == teamID {
// normalize the returned object not to contain empty array references
if len(team.Permissions) == 0 {
team.Permissions = nil
}
if len(team.APIKeys) == 0 {
team.APIKeys = nil
}
if len(team.MappedOIDCGroups) == 0 {
team.MappedOIDCGroups = nil
}

return &team, nil
}
}

return &team, nil
return nil, nil
}

func CreateTeamResourceName(localName string) string {
Expand All @@ -123,3 +168,7 @@ func CreateTeamResourceName(localName string) string {
func CreateTeamPermissionResourceName(localName string) string {
return fmt.Sprintf("dependencytrack_team_permission.%s", localName)
}

func CreateTeamAPIKeyResourceName(localName string) string {
return fmt.Sprintf("dependencytrack_team_api_key.%s", localName)
}

0 comments on commit 2b33a1c

Please sign in to comment.