Skip to content

Commit

Permalink
Pivoted to a registry based framework
Browse files Browse the repository at this point in the history
  • Loading branch information
Ganeshrockz committed Dec 20, 2023
1 parent 619f14d commit 779963a
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 74 deletions.
44 changes: 11 additions & 33 deletions test/acceptance/examples/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,41 @@ package examples
import (
"fmt"
"os"
"strings"
"testing"
"time"

terratestLogger "github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/random"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios"
clusterpeering "github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/cluster-peering"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/ec2"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/fargate"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/hcp"
localityawarerouting "github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/locality-aware-routing"
sameness "github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/service-sameness"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/wan-federation"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/framework/logger"
"github.com/stretchr/testify/require"
)

type ScenarioFunc func(string) scenarios.Scenario

var scenarioFuncs = map[string]ScenarioFunc{
"FARGATE": fargate.New,
"EC2": ec2.New,
"HCP": hcp.New,
"CLUSTER_PEERING": clusterpeering.New,
"WAN_FEDERATION": wan.New,
"LOCALITY_AWARE_ROUTING": localityawarerouting.New,
"SERVICE_SAMENESS": sameness.New,
}

// TestRunScenario accepts a single scenario name as an environment
// variable and executes tests for the same. We want to run each
// scenario as a separate GitHub Action job.
func TestRunScenario(t *testing.T) {
// Setup scenario registry
scenarioRegistry := setupScenarios()

scenarioName := os.Getenv("TEST_SCENARIO")
require.NotEmpty(t, scenarioName)

scenario := getScenario(scenarioName)
require.NotNil(t, scenario, "unexpected scenario name")
scenario, err := scenarioRegistry.Retrieve(scenarioName)
require.NoError(t, err)

initOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: fmt.Sprintf("../../../examples/%s", scenario.GetFolderName()),
TerraformDir: fmt.Sprintf("../../../examples/%s", scenario.FolderName),
NoColor: true,
})
terraform.Init(t, initOptions)

var tfVars map[string]interface{}
retry.RunWith(&retry.Timer{Timeout: 2 * time.Minute, Wait: 10 * time.Second}, t, func(r *retry.R) {
var err error
tfVars, err = scenario.GetTerraformVars()
tfVars, err = scenario.TerraformInputVars()
require.NoError(r, err)
})

Expand Down Expand Up @@ -85,15 +68,10 @@ func TestRunScenario(t *testing.T) {
logger.Log(t, "validation successful!!")
}

func getScenario(name string) scenarios.Scenario {
// This name will be passed as the name input to the terraform apply call.
// This name can be modified inside the individual scenarios too according
// to the scenario's needs.
terraformResourcesName := fmt.Sprintf("ecs-%s", strings.ToLower(random.UniqueId()))
func setupScenarios() scenarios.ScenarioRegistry {
reg := scenarios.NewScenarioRegistry()

if scenario, ok := scenarioFuncs[name]; ok {
return scenario(terraformResourcesName)
}
fargate.RegisterScenario(reg)

return nil
return reg
}
84 changes: 43 additions & 41 deletions test/acceptance/examples/scenarios/fargate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,64 +8,66 @@ import (
"strings"
"testing"

"github.com/gruntwork-io/terratest/modules/random"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/examples/scenarios/common"
"github.com/hashicorp/terraform-aws-consul-ecs/test/acceptance/framework/logger"
"github.com/stretchr/testify/require"
)

type fargate struct {
name string
}
func RegisterScenario(r scenarios.ScenarioRegistry) {
tfResourcesName := strings.ToLower(fmt.Sprintf("ecs-%s", random.UniqueId()))

func New(name string) scenarios.Scenario {
return &fargate{
name: name,
}
r.Register(scenarios.ScenarioRegistration{
Name: "FARGATE",
FolderName: "dev-server-fargate",
TerraformInputVars: getTerraformVars(tfResourcesName),
Validate: validate(tfResourcesName),
})
}

func (f *fargate) GetFolderName() string {
return "dev-server-fargate"
}
func getTerraformVars(tfResName string) scenarios.TerraformInputVarsHook {
return func() (map[string]interface{}, error) {
vars := map[string]interface{}{
"region": "us-east-1",
"name": tfResName,
}

func (f *fargate) GetTerraformVars() (map[string]interface{}, error) {
vars := map[string]interface{}{
"region": "us-east-1",
"name": f.name,
}
publicIP, err := common.GetPublicIP()
if err != nil {
return nil, err
}
vars["lb_ingress_ip"] = publicIP

publicIP, err := common.GetPublicIP()
if err != nil {
return nil, err
return vars, nil
}
vars["lb_ingress_ip"] = publicIP

return vars, nil
}

func (f *fargate) Validate(t *testing.T, outputVars map[string]interface{}) {
logger.Log(t, "Fetching required output terraform variables")
getOutputVariableValue := func(name string) string {
val, ok := outputVars[name].(string)
require.True(t, ok)
return val
}
func validate(tfResName string) scenarios.ValidateHook {
return func(t *testing.T, outputVars map[string]interface{}) {
logger.Log(t, "Fetching required output terraform variables")
getOutputVariableValue := func(name string) string {
val, ok := outputVars[name].(string)
require.True(t, ok)
return val
}

consulServerLBAddr := getOutputVariableValue("consul_server_lb_address")
meshClientLBAddr := getOutputVariableValue("mesh_client_lb_address")
meshClientLBAddr = strings.TrimSuffix(meshClientLBAddr, "/ui")
consulServerLBAddr := getOutputVariableValue("consul_server_lb_address")
meshClientLBAddr := getOutputVariableValue("mesh_client_lb_address")
meshClientLBAddr = strings.TrimSuffix(meshClientLBAddr, "/ui")

logger.Log(t, "Setting up the Consul client")
consulClient, err := common.SetupConsulClient(t, consulServerLBAddr)
require.NoError(t, err)
logger.Log(t, "Setting up the Consul client")
consulClient, err := common.SetupConsulClient(t, consulServerLBAddr)
require.NoError(t, err)

clientAppName := fmt.Sprintf("%s-example-client-app", f.name)
serverAppName := fmt.Sprintf("%s-example-server-app", f.name)
clientAppName := fmt.Sprintf("%s-example-client-app", tfResName)
serverAppName := fmt.Sprintf("%s-example-server-app", tfResName)

consulClient.EnsureServiceReadiness(clientAppName, nil)
consulClient.EnsureServiceReadiness(serverAppName, nil)
consulClient.EnsureServiceReadiness(clientAppName, nil)
consulClient.EnsureServiceReadiness(serverAppName, nil)

// Perform assertions by hitting the client app's LB
logger.Log(t, "calling client app's load balancer to see if the server app is reachable")
common.ValidateFakeServiceResponse(t, meshClientLBAddr, serverAppName)
// Perform assertions by hitting the client app's LB
logger.Log(t, "calling client app's load balancer to see if the server app is reachable")
common.ValidateFakeServiceResponse(t, meshClientLBAddr, serverAppName)
}
}
36 changes: 36 additions & 0 deletions test/acceptance/examples/scenarios/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package scenarios

import "fmt"

type scenarioName string

type registry struct {
scenarios map[scenarioName]ScenarioRegistration
}

func NewScenarioRegistry() ScenarioRegistry {
return &registry{
scenarios: make(map[scenarioName]ScenarioRegistration),
}
}

func (s *registry) Register(reg ScenarioRegistration) error {
if _, ok := s.scenarios[scenarioName(reg.Name)]; ok {
return fmt.Errorf("scenario %s already registered", reg.Name)
}

s.scenarios[scenarioName(reg.Name)] = reg
return nil
}

func (s *registry) Retrieve(name string) (ScenarioRegistration, error) {
scenario, ok := s.scenarios[scenarioName(name)]
if !ok {
return ScenarioRegistration{}, fmt.Errorf("scenario %s is not registered", name)
}

return scenario, nil
}
34 changes: 34 additions & 0 deletions test/acceptance/examples/scenarios/scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,37 @@ type Scenario interface {
// hook will only be called after a successful terraform apply.
Validate(t *testing.T, tfOutput map[string]interface{})
}

// ScenarioRegistry helps us interact with the
// actual registry that holds details about the scenarios.
type ScenarioRegistry interface {
// Register registers a scenario into the registry
Register(ScenarioRegistration) error

// Retrieve retrieves a scenario from the registry
Retrieve(name string) (ScenarioRegistration, error)
}

type TerraformInputVarsHook func() (map[string]interface{}, error)
type ValidateHook func(t *testing.T, tfOutput map[string]interface{})

// ScenarioRegistration is the struct we expect each individual
// scenario to use and register themselves by providing valid
// lifecycle hooks
type ScenarioRegistration struct {
// The name of the scenario. This name should match the value
// of TEST_SCENARIO environment variable which the test uses
// to determine the scenario to run.
Name string

// The name of the example's folder under the `examples/` directory
FolderName string

// List of TF variables that needs to be supplied to the
// example's terraform config.
TerraformInputVars TerraformInputVarsHook

// Validate is the hook called when validations need to be performed on the deployment. This
// hook will only be called after a successful terraform apply.
Validate ValidateHook
}

0 comments on commit 779963a

Please sign in to comment.