Skip to content

Commit

Permalink
add TestHTTPRoutePathRewrite test translation
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahalsmiller committed Feb 27, 2023
1 parent ec4a2e1 commit 0def314
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 41 deletions.
6 changes: 2 additions & 4 deletions test/integration/consul-container/libs/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func NewN(t TestingT, conf Config, count int) (*Cluster, error) {
func New(t TestingT, configs []Config, ports ...int) (*Cluster, error) {
id, err := shortid.Generate()
if err != nil {
return nil, fmt.Errorf("could not generate cluster id: %w", err)
return nil, fmt.Errorf("could not cluster id: %w", err)
}

name := fmt.Sprintf("consul-int-cluster-%s", id)
Expand Down Expand Up @@ -114,7 +114,7 @@ func (c *Cluster) AddN(conf Config, count int, join bool) error {
return c.Add(configs, join)
}

// Add starts agents with the given configurations and joins them to the existing cluster
// Add starts an agent with the given configuration and joins it with the existing cluster
func (c *Cluster) Add(configs []Config, serfJoin bool, ports ...int) (xe error) {
if c.Index == 0 && !serfJoin {
return fmt.Errorf("the first call to Cluster.Add must have serfJoin=true")
Expand Down Expand Up @@ -161,11 +161,9 @@ func (c *Cluster) Add(configs []Config, serfJoin bool, ports ...int) (xe error)
func (c *Cluster) Join(agents []Agent) error {
return c.join(agents, false)
}

func (c *Cluster) JoinExternally(agents []Agent) error {
return c.join(agents, true)
}

func (c *Cluster) join(agents []Agent, skipSerfJoin bool) error {
if len(agents) == 0 {
return nil // no change
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,47 @@ func createCluster(t *testing.T, ports ...int) *libcluster.Cluster {
return cluster
}

func createGateway(gatewayName string, protocol string, listenerPort int) *api.APIGatewayConfigEntry {
return &api.APIGatewayConfigEntry{
Kind: "api-gateway",
Name: gatewayName,
Listeners: []api.APIGatewayListener{
{
Name: "listener",
Port: listenerPort,
Protocol: protocol,
},
},
}
}

func checkGatewayConfigEntry(t *testing.T, client *api.Client, gatewayName string, namespace string) {
require.Eventually(t, func() bool {
entry, _, err := client.ConfigEntries().Get(api.APIGateway, gatewayName, &api.QueryOptions{Namespace: namespace})
assert.NoError(t, err)
if entry == nil {
return false
}
apiEntry := entry.(*api.APIGatewayConfigEntry)
t.Log(entry)
return isAccepted(apiEntry.Status.Conditions)
}, time.Second*10, time.Second*1)
}

func checkHTTPRouteConfigEntry(t *testing.T, client *api.Client, routeName string, namespace string) {
require.Eventually(t, func() bool {
entry, _, err := client.ConfigEntries().Get(api.HTTPRoute, routeName, &api.QueryOptions{Namespace: namespace})
assert.NoError(t, err)
if entry == nil {
return false
}

apiEntry := entry.(*api.HTTPRouteConfigEntry)
t.Log(entry)
return isBound(apiEntry.Status.Conditions)
}, time.Second*10, time.Second*1)
}

func createService(t *testing.T, cluster *libcluster.Cluster, serviceOpts *libservice.ServiceOpts, containerArgs []string) libservice.Service {
node := cluster.Agents[0]
client := node.GetClient()
Expand Down Expand Up @@ -191,7 +232,10 @@ type checkOptions struct {
testName string
}

func checkRoute(t *testing.T, ip string, port int, path string, headers map[string]string, expected checkOptions) {
func checkRoute(t *testing.T, ip string, port int, route string, headers map[string]string, expected checkOptions) {
if expected.testName != "" {
t.Log("running " + expected.testName)
}
const phrase = "hello"

failer := func() *retry.Timer {
Expand All @@ -201,8 +245,11 @@ func checkRoute(t *testing.T, ip string, port int, path string, headers map[stri
client := cleanhttp.DefaultClient()
url := fmt.Sprintf("http://%s:%d", ip, port)

if path != "" {
url += "/" + path
if route != "" {
if route[0] != '/' {
url += "/"
}
url += route
}

retry.RunWith(failer(), t, func(r *retry.R) {
Expand Down
214 changes: 180 additions & 34 deletions test/integration/consul-container/test/gateways/http_route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)

func getNamespace() string {
Expand All @@ -36,6 +35,7 @@ func TestHTTPRouteFlattening(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}

t.Parallel()

//infrastructure set up
Expand Down Expand Up @@ -186,45 +186,18 @@ func TestHTTPRouteFlattening(t *testing.T) {
libassert.CatalogServiceExists(t, client, gatewayName)

//make sure config entries have been properly created
require.Eventually(t, func() bool {
entry, _, err := client.ConfigEntries().Get(api.APIGateway, gatewayName, &api.QueryOptions{Namespace: namespace})
assert.NoError(t, err)
if entry == nil {
return false
}
apiEntry := entry.(*api.APIGatewayConfigEntry)
t.Log(entry)
return isAccepted(apiEntry.Status.Conditions)
}, time.Second*10, time.Second*1)

require.Eventually(t, func() bool {
entry, _, err := client.ConfigEntries().Get(api.HTTPRoute, routeOneName, &api.QueryOptions{Namespace: namespace})
assert.NoError(t, err)
if entry == nil {
return false
}

apiEntry := entry.(*api.HTTPRouteConfigEntry)
t.Log(entry)
return isBound(apiEntry.Status.Conditions)
}, time.Second*10, time.Second*1)

require.Eventually(t, func() bool {
entry, _, err := client.ConfigEntries().Get(api.HTTPRoute, routeTwoName, nil)
assert.NoError(t, err)
if entry == nil {
return false
}

apiEntry := entry.(*api.HTTPRouteConfigEntry)
return isBound(apiEntry.Status.Conditions)
}, time.Second*10, time.Second*1)
checkGatewayConfigEntry(t, client, gatewayName, namespace)
checkHTTPRouteConfigEntry(t, client, routeOneName, namespace)
checkHTTPRouteConfigEntry(t, client, routeTwoName, namespace)

//gateway resolves routes

ip := "localhost"
gatewayPort, err := gatewayService.GetPort(listenerPort)
assert.NoError(t, err)

//route 2 with headers

//Same v2 path with and without header
checkRoute(t, ip, gatewayPort, "v2", map[string]string{
"Host": "test.foo",
Expand Down Expand Up @@ -256,3 +229,176 @@ func TestHTTPRouteFlattening(t *testing.T) {
}, checkOptions{debug: false, statusCode: service1ResponseCode, testName: "service1, v2 path with v2 hostname"})

}

func TestHTTPRoutePathRewrite(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}

t.Parallel()

//infrastructure set up
listenerPort := 6001
//create cluster
cluster := createCluster(t, listenerPort)
client := cluster.Agents[0].GetClient()
invalidServiceResponseCode := 400
validServiceResponseCode := 200
pathToRewrite := "/v1/api"

invalidService := createService(t, cluster, &libservice.ServiceOpts{
Name: "invalid",
ID: "invalid",
HTTPPort: 8080,
GRPCPort: 8081,
}, []string{
//customizes response code so we can distinguish between which service is responding
"-echo-server-default-params", fmt.Sprintf("status=%d", invalidServiceResponseCode),
})
validService := createService(t, cluster, &libservice.ServiceOpts{
Name: "valid",
ID: "valid",
//TODO we can potentially get conflicts if these ports are the same and the tests are running in parralel
//need to poll for available ports to avoid conflicts
HTTPPort: 8079,
GRPCPort: 8078,
}, []string{
"-echo-server-default-params", fmt.Sprintf("status=%d", validServiceResponseCode),
"-echo-debug-path", pathToRewrite,
},
)

namespace := getNamespace()
gatewayName := randomName("gw", 16)
invalidRouteName := randomName("route", 16)
validRouteName := randomName("route", 16)
validPath := "/foo"
invalidPath := "/bar"

//write config entries
proxyDefaults := &api.ProxyConfigEntry{
Kind: api.ProxyDefaults,
Name: api.ProxyConfigGlobal,
Namespace: namespace,
Config: map[string]interface{}{
"protocol": "http",
},
}

_, _, err := client.ConfigEntries().Set(proxyDefaults, nil)
assert.NoError(t, err)

apiGateway := createGateway(gatewayName, "http", listenerPort)

invalidRoute := &api.HTTPRouteConfigEntry{
Kind: api.HTTPRoute,
Name: invalidRouteName,
Parents: []api.ResourceReference{
{
Kind: api.APIGateway,
Name: gatewayName,
Namespace: namespace,
},
},
Hostnames: []string{
"test.foo",
},
Namespace: namespace,
Rules: []api.HTTPRouteRule{
{
Filters: api.HTTPFilters{
URLRewrite: &api.URLRewrite{
Path: "/v1/invalid",
},
},
Services: []api.HTTPService{
{
Name: invalidService.GetServiceName(),
Namespace: namespace,
},
},
Matches: []api.HTTPMatch{
{
Path: api.HTTPPathMatch{
Match: api.HTTPPathMatchPrefix,
Value: "/bar",
},
},
},
},
},
}

validRoute := &api.HTTPRouteConfigEntry{
Kind: api.HTTPRoute,
Name: validRouteName,
Parents: []api.ResourceReference{
{
Kind: api.APIGateway,
Name: gatewayName,
Namespace: namespace,
},
},
Hostnames: []string{
"test.foo",
},
Namespace: namespace,
Rules: []api.HTTPRouteRule{
{
Filters: api.HTTPFilters{
URLRewrite: &api.URLRewrite{
Path: "/v1/api",
},
},
Services: []api.HTTPService{
{
Name: validService.GetServiceName(),
Namespace: namespace,
},
},
Matches: []api.HTTPMatch{
{
Path: api.HTTPPathMatch{
Match: api.HTTPPathMatchPrefix,
Value: "/foo",
},
},
},
},
},
}

_, _, err = client.ConfigEntries().Set(apiGateway, nil)
assert.NoError(t, err)
_, _, err = client.ConfigEntries().Set(invalidRoute, nil)
assert.NoError(t, err)
_, _, err = client.ConfigEntries().Set(validRoute, nil)
assert.NoError(t, err)

//create gateway service
gatewayService, err := libservice.NewGatewayService(context.Background(), gatewayName, "api", cluster.Agents[0], listenerPort)
require.NoError(t, err)
libassert.CatalogServiceExists(t, client, gatewayName)

//make sure config entries have been properly created
checkGatewayConfigEntry(t, client, gatewayName, namespace)
checkHTTPRouteConfigEntry(t, client, invalidRouteName, namespace)
checkHTTPRouteConfigEntry(t, client, validRouteName, namespace)

ip := "localhost"
gatewayPort, err := gatewayService.GetPort(listenerPort)
assert.NoError(t, err)

//TODO these were the assertions we had in the original test, but I'm unclear on why invalid is invalid

//hit invalid service by hitting root path
checkRoute(t, ip, gatewayPort, invalidPath, map[string]string{
"Host": "test.foo",
}, checkOptions{debug: false, statusCode: invalidServiceResponseCode, testName: "invlaid service"})

//hit valid path, double check that the response body returns properly
checkRoute(t, ip, gatewayPort, validPath, map[string]string{
"Host": "test.foo",
}, checkOptions{debug: true, statusCode: validServiceResponseCode, testName: "valid service"})

}

0 comments on commit 0def314

Please sign in to comment.