Skip to content

Commit

Permalink
E2E test
Browse files Browse the repository at this point in the history
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
  • Loading branch information
lubronzhan committed Feb 18, 2024
1 parent c00ad0b commit 8509331
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 6 deletions.
8 changes: 3 additions & 5 deletions internal/dag/gatewayapi_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1433,7 +1433,7 @@ func (p *GatewayAPIProcessor) computeHTTPRouteForListener(
routes = append(routes, routesPerRule...)
}

// check all the routes at once in case there is conclict
// check all the routes at once in case there is conflict
if p.hasConflictRoute(listener, hosts, routes) {
// skip adding the route to svhost or vhost since it's marked as conflict route
routeAccessor.AddCondition(
Expand Down Expand Up @@ -2447,10 +2447,8 @@ func sortRoutes(m map[types.NamespacedName]*gatewayapi_v1.HTTPRoute) []*gatewaya
sort.SliceStable(routes, func(i, j int) bool {
// if the creation time is the same, compare the route name
if routes[i].CreationTimestamp.Equal(&routes[j].CreationTimestamp) {
if routes[i].Name == routes[j].Name {
return routes[i].Namespace < routes[j].Namespace
}
return routes[i].Name < routes[j].Name
return fmt.Sprintf("%s/%s", routes[i].Namespace, routes[i].Name) <
fmt.Sprintf("%s/%s", routes[j].Namespace, routes[j].Name)
}
return routes[i].CreationTimestamp.Before(&routes[j].CreationTimestamp)
})
Expand Down
3 changes: 2 additions & 1 deletion internal/dag/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5511,6 +5511,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) {
"test.projectcontour.io",
},
Rules: []gatewayapi_v1.HTTPRouteRule{{
// changed to different matches in case there is conflict with above HTTPRoute
Matches: gatewayapi.HTTPRouteMatch(gatewayapi_v1.PathMatchExact, "/"),
BackendRefs: gatewayapi.HTTPBackendRef("kuard", 8080, 1),
}},
Expand Down Expand Up @@ -5575,7 +5576,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) {
},
Headers: []gatewayapi_v1.HTTPHeaderMatch{
{
Type: ptr.To(gatewayapi_v1.HeaderMatchExact), // <---- unknown type to break the test
Type: ptr.To(gatewayapi_v1.HeaderMatchExact),
Name: gatewayapi_v1.HTTPHeaderName("foo"),
Value: "bar",
},
Expand Down
2 changes: 2 additions & 0 deletions test/e2e/gateway/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ var _ = Describe("Gateway API", func() {
f.NamespacedTest("gateway-request-redirect-rule", testWithHTTPGateway(testRequestRedirectRule))

f.NamespacedTest("gateway-backend-tls-policy", testWithHTTPGateway(testBackendTLSPolicy))

f.NamespacedTest("gateway-httproute-conflict-match", testWithHTTPGateway(testHTTPRouteConflictMatch))
})

Describe("Gateway with one HTTP listener and one HTTPS listener", func() {
Expand Down
86 changes: 86 additions & 0 deletions test/e2e/gateway/http_route_conflict_match_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright Project Contour Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build e2e

package gateway

import (
. "github.com/onsi/ginkgo/v2"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1"

"github.com/projectcontour/contour/internal/gatewayapi"
"github.com/projectcontour/contour/test/e2e"
)

func testHTTPRouteConflictMatch(namespace string, gateway types.NamespacedName) {
Specify("Creates two http routes, second one has conflict match condition as the first one", func() {
By("create httproute-1 first")
route1 := &gatewayapi_v1.HTTPRoute{
ObjectMeta: meta_v1.ObjectMeta{
Namespace: namespace,
Name: "httproute-1",
},
Spec: gatewayapi_v1.HTTPRouteSpec{
Hostnames: []gatewayapi_v1.Hostname{"queryparams.gateway.projectcontour.io"},
CommonRouteSpec: gatewayapi_v1.CommonRouteSpec{
ParentRefs: []gatewayapi_v1.ParentReference{
gatewayapi.GatewayParentRef(gateway.Namespace, gateway.Name),
},
},
Rules: []gatewayapi_v1.HTTPRouteRule{
{
Matches: []gatewayapi_v1.HTTPRouteMatch{
{QueryParams: gatewayapi.HTTPQueryParamMatches(map[string]string{"animal": "whale"})},
},
BackendRefs: gatewayapi.HTTPBackendRef("echo-1", 80, 1),
},
{
Matches: []gatewayapi_v1.HTTPRouteMatch{
{QueryParams: gatewayapi.HTTPQueryParamMatches(map[string]string{"animal": "dolphin"})},
},
BackendRefs: gatewayapi.HTTPBackendRef("echo-2", 80, 1),
},
},
},
}
f.CreateHTTPRouteAndWaitFor(route1, e2e.HTTPRouteAccepted)

By("create httproute-2 with conflicted matches")
route2 := &gatewayapi_v1.HTTPRoute{
ObjectMeta: meta_v1.ObjectMeta{
Namespace: namespace,
Name: "httproute-2",
},
Spec: gatewayapi_v1.HTTPRouteSpec{
Hostnames: []gatewayapi_v1.Hostname{"queryparams.gateway.projectcontour.io"},
CommonRouteSpec: gatewayapi_v1.CommonRouteSpec{
ParentRefs: []gatewayapi_v1.ParentReference{
gatewayapi.GatewayParentRef(gateway.Namespace, gateway.Name),
},
},
Rules: []gatewayapi_v1.HTTPRouteRule{
{
Matches: []gatewayapi_v1.HTTPRouteMatch{
{QueryParams: gatewayapi.HTTPQueryParamMatches(map[string]string{"animal": "whale"})},
},
BackendRefs: gatewayapi.HTTPBackendRef("echo-1", 80, 1),
},
},
},
}
f.CreateHTTPRouteAndWaitFor(route2, e2e.HTTPRouteNotAcceptedDueToConflict)
})
}
29 changes: 29 additions & 0 deletions test/e2e/gatewayapi_predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

"github.com/projectcontour/contour/internal/status"
)

// GatewayClassAccepted returns true if the gateway has a .status.conditions
Expand Down Expand Up @@ -119,6 +121,23 @@ func HTTPRouteAccepted(route *gatewayapi_v1.HTTPRoute) bool {
return false
}

// HTTPRouteNotAcceptedDueToConflict returns true if the route has a .status.conditions
// entry of "Accepted: false" && "Reason: RouteConflict" && "Message: HTTPRoute's Match has
// conflict with other HTTPRoute's Match"
func HTTPRouteNotAcceptedDueToConflict(route *gatewayapi_v1.HTTPRoute) bool {
if route == nil {
return false
}

for _, gw := range route.Status.Parents {
if conditionExistsWithAllKeys(gw.Conditions, string(gatewayapi_v1.RouteConditionAccepted), meta_v1.ConditionFalse, string(status.ReasonRouteConflict), "HTTPRoute's Match has conflict with other HTTPRoute's Match") {
return false
}
}

return false
}

// HTTPRouteIgnoredByContour returns true if the route has an empty .status.parents.conditions list
func HTTPRouteIgnoredByContour(route *gatewayapi_v1.HTTPRoute) bool {
if route == nil {
Expand Down Expand Up @@ -194,3 +213,13 @@ func conditionExists(conditions []meta_v1.Condition, conditionType string, condi

return false
}

func conditionExistsWithAllKeys(conditions []meta_v1.Condition, conditionType string, conditionStatus meta_v1.ConditionStatus, reason, message string) bool {
for _, cond := range conditions {
if cond.Type == conditionType && cond.Status == conditionStatus && cond.Reason == reason && cond.Message == message {
return true
}
}

return false
}

0 comments on commit 8509331

Please sign in to comment.