Skip to content

Commit

Permalink
test: slight refactoring ahead of peering testing improvements (#17387)
Browse files Browse the repository at this point in the history
  • Loading branch information
rboyer authored May 16, 2023
1 parent 8f6b9fe commit 2f5256e
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 20 deletions.
72 changes: 58 additions & 14 deletions test/integration/consul-container/libs/assert/envoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package assert
import (
"fmt"
"io"
"net/http"
"net/url"
"regexp"
"strconv"
Expand All @@ -14,15 +15,29 @@ import (
"time"

"github.com/hashicorp/consul/sdk/testutil/retry"
libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster"
"github.com/hashicorp/consul/test/integration/consul-container/libs/utils"
"github.com/hashicorp/go-cleanhttp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

libcluster "github.com/hashicorp/consul/test/integration/consul-container/libs/cluster"
"github.com/hashicorp/consul/test/integration/consul-container/libs/utils"
)

// GetEnvoyListenerTCPFilters validates that proxy was configured with tcp protocol and one rbac listener filter
func GetEnvoyListenerTCPFilters(t *testing.T, adminPort int) {
require.True(t, adminPort > 0)

GetEnvoyListenerTCPFiltersWithClient(
t,
cleanhttp.DefaultClient(),
fmt.Sprintf("localhost:%d", adminPort),
)
}
func GetEnvoyListenerTCPFiltersWithClient(
t *testing.T,
client *http.Client,
addr string,
) {
var (
dump string
err error
Expand All @@ -32,7 +47,7 @@ func GetEnvoyListenerTCPFilters(t *testing.T, adminPort int) {
}

retry.RunWith(failer(), t, func(r *retry.R) {
dump, _, err = GetEnvoyOutput(adminPort, "config_dump", map[string]string{})
dump, _, err = GetEnvoyOutputWithClient(client, addr, "config_dump", map[string]string{})
if err != nil {
r.Fatal("could not fetch envoy configuration")
}
Expand All @@ -55,30 +70,55 @@ func GetEnvoyListenerTCPFilters(t *testing.T, adminPort int) {
require.Contains(t, filteredResult, "envoy.filters.network.tcp_proxy")
}

// func GetEnvoyOutputWithClient(client *http.Client, addr string, path string, query map[string]string) (string, int, error) {

// AssertUpstreamEndpointStatus validates that proxy was configured with provided clusterName in the healthStatus
func AssertUpstreamEndpointStatus(t *testing.T, adminPort int, clusterName, healthStatus string, count int) {
var (
clusters string
err error
require.True(t, adminPort > 0)
AssertUpstreamEndpointStatusWithClient(
t,
cleanhttp.DefaultClient(),
fmt.Sprintf("localhost:%d", adminPort),
clusterName,
healthStatus,
count,
)
}
func AssertUpstreamEndpointStatusWithClient(
t *testing.T,
client *http.Client,
addr string,
clusterName string,
healthStatus string,
count int,
) {
require.NotNil(t, client)
require.NotEmpty(t, addr)
failer := func() *retry.Timer {
return &retry.Timer{Timeout: 30 * time.Second, Wait: 500 * time.Millisecond}
}

retry.RunWith(failer(), t, func(r *retry.R) {
clusters, _, err = GetEnvoyOutput(adminPort, "clusters", map[string]string{"format": "json"})
clusters, statusCode, err := GetEnvoyOutputWithClient(client, addr, "clusters", map[string]string{"format": "json"})
if err != nil {
r.Fatal("could not fetch envoy clusters")
}

filter := fmt.Sprintf(`.cluster_statuses[] | select(.name|contains("%s")) | [.host_statuses[].health_status.eds_health_status] | [select(.[] == "%s")] | length`, clusterName, healthStatus)
require.Equal(r, 200, statusCode)

filter := fmt.Sprintf(
`.cluster_statuses[]
| select(.name|contains("%s"))
| [.host_statuses[].health_status.eds_health_status]
| [select(.[] == "%s")]
| length`,
clusterName, healthStatus)
results, err := utils.JQFilter(clusters, filter)
require.NoErrorf(r, err, "could not found cluster name %s", clusterName)
require.NoErrorf(r, err, "could not found cluster name %s in \n%s", clusterName, clusters)
require.Len(r, results, 1) // the final part of the pipeline is "length" which only ever returns 1 result

resultToString := strings.Join(results, " ")
result, err := strconv.Atoi(resultToString)
result, err := strconv.Atoi(results[0])
assert.NoError(r, err)
require.Equal(r, count, result)
require.Equal(r, count, result, "original results: %v", clusters)
})
}

Expand Down Expand Up @@ -240,8 +280,12 @@ func AssertEnvoyRunning(t *testing.T, port int) {

func GetEnvoyOutput(port int, path string, query map[string]string) (string, int, error) {
client := cleanhttp.DefaultClient()
return GetEnvoyOutputWithClient(client, fmt.Sprintf("localhost:%d", port), path, query)
}

func GetEnvoyOutputWithClient(client *http.Client, addr string, path string, query map[string]string) (string, int, error) {
var u url.URL
u.Host = fmt.Sprintf("localhost:%d", port)
u.Host = addr
u.Scheme = "http"
if path != "" {
u.Path = path
Expand Down
22 changes: 20 additions & 2 deletions test/integration/consul-container/libs/assert/peering.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@ import (

// PeeringStatus verifies the peering connection is the specified state with a default retry.
func PeeringStatus(t *testing.T, client *api.Client, peerName string, status api.PeeringState) {
PeeringStatusOpts(t, client, peerName, status, nil)
}

// PeeringStatusOpts verifies the peering connection is the specified
// state with a default retry with options.
func PeeringStatusOpts(t *testing.T, client *api.Client, peerName string, status api.PeeringState, opts *api.QueryOptions) {
failer := func() *retry.Timer {
return &retry.Timer{Timeout: 180 * time.Second, Wait: defaultWait}
}

retry.RunWith(failer(), t, func(r *retry.R) {
peering, _, err := client.Peerings().Read(context.Background(), peerName, &api.QueryOptions{})
peering, _, err := client.Peerings().Read(context.Background(), peerName, opts)
if err != nil {
r.Fatal("error reading peering data")
}
if peering == nil {
r.Fatal("peering not found")
}
if status != peering.State {
r.Fatal("peering state did not match: got ", peering.State, " want ", status)
}
Expand All @@ -31,15 +40,24 @@ func PeeringStatus(t *testing.T, client *api.Client, peerName string, status api

// PeeringExports verifies the correct number of exported services with a default retry.
func PeeringExports(t *testing.T, client *api.Client, peerName string, exports int) {
PeeringExportsOpts(t, client, peerName, exports, nil)
}

// PeeringExportsOpts verifies the correct number of exported services
// with a default retry with options.
func PeeringExportsOpts(t *testing.T, client *api.Client, peerName string, exports int, opts *api.QueryOptions) {
failer := func() *retry.Timer {
return &retry.Timer{Timeout: defaultTimeout, Wait: defaultWait}
}

retry.RunWith(failer(), t, func(r *retry.R) {
peering, _, err := client.Peerings().Read(context.Background(), peerName, &api.QueryOptions{})
peering, _, err := client.Peerings().Read(context.Background(), peerName, opts)
if err != nil {
r.Fatal("error reading peering data")
}
if peering == nil {
r.Fatal("peering not found")
}
if exports != len(peering.StreamStatus.ExportedServices) {
r.Fatal("peering exported services did not match: got ", len(peering.StreamStatus.ExportedServices), " want ", exports)
}
Expand Down
30 changes: 26 additions & 4 deletions test/integration/consul-container/libs/assert/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import (

"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/testutil/retry"
libservice "github.com/hashicorp/consul/test/integration/consul-container/libs/service"
"github.com/stretchr/testify/assert"

libservice "github.com/hashicorp/consul/test/integration/consul-container/libs/service"
)

const (
Expand Down Expand Up @@ -55,22 +56,39 @@ func CatalogNodeExists(t *testing.T, c *api.Client, nodeName string) {
func HTTPServiceEchoes(t *testing.T, ip string, port int, path string) {
doHTTPServiceEchoes(t, ip, port, path, nil)
}
func HTTPServiceEchoesWithClient(t *testing.T, client *http.Client, addr string, path string) {
doHTTPServiceEchoesWithClient(t, client, addr, path, nil)
}

func HTTPServiceEchoesResHeader(t *testing.T, ip string, port int, path string, expectedResHeader map[string]string) {
doHTTPServiceEchoes(t, ip, port, path, expectedResHeader)
}
func HTTPServiceEchoesResHeaderWithClient(t *testing.T, client *http.Client, addr string, path string, expectedResHeader map[string]string) {
doHTTPServiceEchoesWithClient(t, client, addr, path, expectedResHeader)
}

// HTTPServiceEchoes verifies that a post to the given ip/port combination returns the data
// in the response body. Optional path can be provided to differentiate requests.
func doHTTPServiceEchoes(t *testing.T, ip string, port int, path string, expectedResHeader map[string]string) {
client := cleanhttp.DefaultClient()
addr := fmt.Sprintf("%s:%d", ip, port)
doHTTPServiceEchoesWithClient(t, client, addr, path, expectedResHeader)
}

func doHTTPServiceEchoesWithClient(
t *testing.T,
client *http.Client,
addr string,
path string,
expectedResHeader map[string]string,
) {
const phrase = "hello"

failer := func() *retry.Timer {
return &retry.Timer{Timeout: defaultHTTPTimeout, Wait: defaultHTTPWait}
}

client := cleanhttp.DefaultClient()
url := fmt.Sprintf("http://%s:%d", ip, port)
url := "http://" + addr

if path != "" {
url += "/" + path
Expand All @@ -85,6 +103,10 @@ func doHTTPServiceEchoes(t *testing.T, ip string, port int, path string, expecte
}
defer res.Body.Close()

statusCode := res.StatusCode
t.Logf("...got response code %d", statusCode)
require.Equal(r, 200, statusCode)

body, err := io.ReadAll(res.Body)
if err != nil {
r.Fatal("could not read response body ", url)
Expand Down Expand Up @@ -166,7 +188,7 @@ func AssertFortioNameWithClient(t *testing.T, urlbase string, name string, reqHo

m := fortioNameRE.FindStringSubmatch(string(body))
require.GreaterOrEqual(r, len(m), 2)
t.Logf("got response from server name %s", m[1])
t.Logf("got response from server name %q expect %q", m[1], name)
assert.Equal(r, name, m[1])
})
}
Expand Down
32 changes: 32 additions & 0 deletions test/integration/consul-container/libs/utils/tenancy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package utils

import "github.com/hashicorp/consul/api"

func PartitionOrDefault(name string) string {
if name == "" {
return "default"
}
return name
}
func NamespaceOrDefault(name string) string {
if name == "" {
return "default"
}
return name
}

func DefaultToEmpty(name string) string {
if name == "default" {
return ""
}
return name
}

// PartitionQueryOptions returns an *api.QueryOptions with the given partition
// field set only if the partition is non-default. This helps when writing
// tests for joint use in OSS and ENT.
func PartitionQueryOptions(partition string) *api.QueryOptions {
return &api.QueryOptions{
Partition: DefaultToEmpty(partition),
}
}
2 changes: 2 additions & 0 deletions test/integration/consul-container/libs/utils/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ func GetLatestImageName() string {
return LatestImageName
}

func IsEnterprise() bool { return isInEnterpriseRepo }

func DockerImage(image, version string) string {
v := image + ":" + version
if strings.Contains(image, DefaultImageNameENT) && isSemVer(version) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ package utils
const (
defaultImageName = DefaultImageNameOSS
ImageVersionSuffix = ""
isInEnterpriseRepo = false
)

0 comments on commit 2f5256e

Please sign in to comment.