Skip to content

Commit

Permalink
tests for routing_zone_constraint resource
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismarget-j committed Dec 20, 2024
1 parent dce8ca5 commit da40ca6
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 0 deletions.
1 change: 1 addition & 0 deletions apstra/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var (
ResourceDatacenterGenericSystem = resourceDatacenterGenericSystem{}
ResourceDatacenterIpLinkAddressing = resourceDatacenterIpLinkAddressing{}
ResourceDatacenterRoutingZone = resourceDatacenterRoutingZone{}
ResourceDatacenterRoutingZoneConstraint = resourceDatacenterRoutingZoneConstraint{}
ResourceDatacenterVirtualNetwork = resourceDatacenterVirtualNetwork{}
ResourceFreeformAllocGroup = resourceFreeformAllocGroup{}
ResourceFreeformBlueprint = resourceFreeformBlueprint{}
Expand Down
223 changes: 223 additions & 0 deletions apstra/resource_datacenter_routing_zone_constraint_integration_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,224 @@
package tfapstra_test

import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/apstra-go-sdk/apstra/enum"
tfapstra "github.com/Juniper/terraform-provider-apstra/apstra"
testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/stretchr/testify/require"
"strconv"
"testing"
)

const (
resourceDataCenterRoutingZoneConstraintHCL = `resource %q %q {
blueprint_id = %q // required attribute
name = %q // required attribute
routing_zones_list_constraint = %q // required attribute
max_count_constraint = %s
constraints = %s
}
data %[1]q "by_id" {
blueprint_id = %[3]q
id = %[1]s.%[2]s.id
depends_on = [%[1]s.%[2]s]
}
data %[1]q "by_name" {
blueprint_id = %[3]q
name = %[1]s.%[2]s.name
depends_on = [%[1]s.%[2]s]
}
`
)

type testRoutingZoneConstraint struct {
name string
MaxCountConstraint *int
RoutingZoneListConstraint enum.RoutingZoneConstraintMode
Constraints []string
}

func (o testRoutingZoneConstraint) render(bpId apstra.ObjectId, rType, rName string) string {
return fmt.Sprintf(resourceDataCenterRoutingZoneConstraintHCL,
rType, rName,
bpId,
o.name,
o.RoutingZoneListConstraint,
intPtrOrNull(o.MaxCountConstraint),
stringSliceOrNull(o.Constraints),
)
}

func (o testRoutingZoneConstraint) testChecks(t testing.TB, bpId apstra.ObjectId, rType, rName string) testChecks {
result := newTestChecks(rType + "." + rName)

// required and computed attributes can always be checked
result.append(t, "TestCheckResourceAttrSet", "id")
result.append(t, "TestCheckResourceAttr", "blueprint_id", bpId.String())
result.append(t, "TestCheckResourceAttr", "name", o.name)
result.append(t, "TestCheckResourceAttr", "routing_zones_list_constraint", o.RoutingZoneListConstraint.String())

if o.MaxCountConstraint == nil {
result.append(t, "TestCheckNoResourceAttr", "max_count_constraint")
} else {
result.append(t, "TestCheckResourceAttr", "max_count_constraint", strconv.Itoa(*o.MaxCountConstraint))
}

result.append(t, "TestCheckResourceAttr", "constraints.#", strconv.Itoa(len(o.Constraints)))
for _, constraint := range o.Constraints {
result.append(t, "TestCheckTypeSetElemAttr", "constraints.*", constraint)
}

return result
}

func TestResourceDatacenterRoutingZoneConstraint(t *testing.T) {
ctx := context.Background()

// create a blueprint
bp := testutils.BlueprintA(t, ctx)

routingZoneIds := make([]string, acctest.RandIntRange(5, 10))
for i := range routingZoneIds {
label := acctest.RandString(6)
id, err := bp.CreateSecurityZone(ctx, &apstra.SecurityZoneData{
Label: label,
SzType: apstra.SecurityZoneTypeEVPN,
VrfName: label,
})
require.NoError(t, err)
routingZoneIds[i] = id.String()
}

type testStep struct {
config testRoutingZoneConstraint
}

type testCase struct {
steps []testStep
versionConstraints version.Constraints
}

testCases := map[string]testCase{
"start_minimal": {
steps: []testStep{
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
RoutingZoneListConstraint: enum.RoutingZoneConstraintModeNone,
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
MaxCountConstraint: utils.ToPtr(acctest.RandIntRange(10, 100)),
RoutingZoneListConstraint: oneOf(enum.RoutingZoneConstraintModeAllow, enum.RoutingZoneConstraintModeDeny),
Constraints: randomSelection(routingZoneIds, len(routingZoneIds)/2),
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
RoutingZoneListConstraint: enum.RoutingZoneConstraintModeNone,
},
},
},
},
"start_maximal": {
steps: []testStep{
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
MaxCountConstraint: utils.ToPtr(acctest.RandIntRange(10, 100)),
RoutingZoneListConstraint: oneOf(enum.RoutingZoneConstraintModeAllow, enum.RoutingZoneConstraintModeDeny),
Constraints: randomSelection(routingZoneIds, len(routingZoneIds)/2),
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
MaxCountConstraint: utils.ToPtr(acctest.RandIntRange(10, 100)),
RoutingZoneListConstraint: oneOf(enum.RoutingZoneConstraintModeAllow, enum.RoutingZoneConstraintModeDeny),
Constraints: randomSelection(routingZoneIds, len(routingZoneIds)/2),
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
RoutingZoneListConstraint: enum.RoutingZoneConstraintModeAllow,
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
RoutingZoneListConstraint: enum.RoutingZoneConstraintModeDeny,
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
RoutingZoneListConstraint: enum.RoutingZoneConstraintModeNone,
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
MaxCountConstraint: utils.ToPtr(acctest.RandIntRange(10, 100)),
RoutingZoneListConstraint: oneOf(enum.RoutingZoneConstraintModeAllow, enum.RoutingZoneConstraintModeDeny),
Constraints: randomSelection(routingZoneIds, len(routingZoneIds)/2),
},
},
{
config: testRoutingZoneConstraint{
name: acctest.RandString(6),
MaxCountConstraint: utils.ToPtr(acctest.RandIntRange(10, 100)),
RoutingZoneListConstraint: oneOf(enum.RoutingZoneConstraintModeAllow, enum.RoutingZoneConstraintModeDeny),
Constraints: randomSelection(routingZoneIds, len(routingZoneIds)/2),
},
},
},
},
}

resourceType := tfapstra.ResourceName(ctx, &tfapstra.ResourceDatacenterRoutingZoneConstraint)

for tName, tCase := range testCases {
t.Run(tName, func(t *testing.T) {
t.Parallel()

if !tCase.versionConstraints.Check(version.Must(version.NewVersion(bp.Client().ApiVersion()))) {
t.Skipf("test case %s requires Apstra %s", tName, tCase.versionConstraints.String())
}

steps := make([]resource.TestStep, len(tCase.steps))
for i, step := range tCase.steps {
config := step.config.render(bp.Id(), resourceType, tName)
checks := step.config.testChecks(t, bp.Id(), resourceType, tName)

chkLog := checks.string()
stepName := fmt.Sprintf("test case %q step %d", tName, i+1)

t.Logf("\n// ------ begin config for %s ------\n%s// -------- end config for %s ------\n\n", stepName, config, stepName)
t.Logf("\n// ------ begin checks for %s ------\n%s// -------- end checks for %s ------\n\n", stepName, chkLog, stepName)

steps[i] = resource.TestStep{
Config: insecureProviderConfigHCL + config,
Check: resource.ComposeAggregateTestCheckFunc(checks.checks...),
}
}

resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: steps,
})
})
}
}
22 changes: 22 additions & 0 deletions apstra/test_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"math"
"math/rand"
"net"
Expand Down Expand Up @@ -260,6 +261,27 @@ func randomIPs(t testing.TB, n int, ipv4Cidr, ipv6Cidr string) []string {
return result
}

func randomSelection[A comparable](s []A, n int) []A {
l := len(s)
if l < n {
log.Panicf("cannot randomly select %d members from a set of %d", n, l)
}

m := make(map[A]struct{}, n)
for len(m) < n {
m[s[rand.Intn(l)]] = struct{}{}
}

result := make([]A, n)
i := 0
for k := range m {
result[i] = k
i++
}

return result
}

func randomStrings(strCount int, strLen int) []string {
result := make([]string, strCount)
for i := 0; i < strCount; i++ {
Expand Down

0 comments on commit da40ca6

Please sign in to comment.