Skip to content

Commit

Permalink
Merge pull request #580 from YaoZengzeng/waypoint-testcase
Browse files Browse the repository at this point in the history
add some waypoint related E2E test cases
  • Loading branch information
kmesh-bot authored Jul 17, 2024
2 parents 7b62cc3 + a0cff6e commit 781fc97
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 6 deletions.
7 changes: 7 additions & 0 deletions test/e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Kmesh E2E test

Kmesh E2E test is used to validate the system as a whole, ensuring that all the individual components and integrations work together seamlessly.

It's integrated into CI to ensure that each merge of code will not break existing functions. You can also run it locally during development for self-testing. It plays an important role in maintaining the stability and availability of Kmesh.

NOTE: Kmesh E2E test framework and test cases is heavily inspired by istio integration framework (https://github.com/istio/istio/tree/master/tests/integration), both in architecture and code.
228 changes: 225 additions & 3 deletions test/e2e/baseline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,23 @@
* limitations under the License.
*/

// NOTE: THE CODE IN THIS FILE IS MAINLY REFERENCED FROM ISTIO INTEGRATION
// FRAMEWORK(https://github.com/istio/istio/tree/master/tests/integration)
// AND ADAPTED FOR KMESH.

package kmesh

import (
"fmt"
"strings"
"testing"
"time"

"istio.io/istio/pkg/test/echo/common/scheme"
"istio.io/istio/pkg/test/framework"
"istio.io/istio/pkg/test/framework/components/echo"
"istio.io/istio/pkg/test/framework/components/echo/check"
"istio.io/istio/pkg/util/sets"
)

var (
Expand Down Expand Up @@ -71,7 +77,7 @@ spec:
- match:
- headers:
user:
exact: istio-custom-user
exact: kmesh-custom-user
route:
- destination:
host: "{{.Destination}}"
Expand Down Expand Up @@ -121,7 +127,7 @@ spec:
if opt.HTTP.Headers == nil {
opt.HTTP.Headers = map[string][]string{}
}
opt.HTTP.Headers.Set("user", "istio-custom-user")
opt.HTTP.Headers.Set("user", "kmesh-custom-user")
opt.Check = check.And(
check.OK(),
func(result echo.CallResult, _ error) error {
Expand All @@ -132,7 +138,205 @@ spec:
}
return nil
})
opt.HTTP.Headers.Set("user", "istio-custom-user")
opt.HTTP.Headers.Set("user", "kmesh-custom-user")
src.CallOrFail(t, opt)
})
})
}

func TestServerSideLB(t *testing.T) {
framework.NewTest(t).Run(func(t framework.TestContext) {
runTestToServiceWaypoint(t, func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions) {
// Need HTTP
if opt.Scheme != scheme.HTTP {
return
}
var singleHost echo.Checker = func(result echo.CallResult, _ error) error {
hostnames := make([]string, len(result.Responses))
for i, r := range result.Responses {
hostnames[i] = r.Hostname
}
unique := sets.SortedList(sets.New(hostnames...))
if len(unique) != 1 {
return fmt.Errorf("excepted only one destination, got: %v", unique)
}
return nil
}
var multipleHost echo.Checker = func(result echo.CallResult, _ error) error {
hostnames := make([]string, len(result.Responses))
for i, r := range result.Responses {
hostnames[i] = r.Hostname
}
unique := sets.SortedList(sets.New(hostnames...))
want := dst.WorkloadsOrFail(t)
wn := []string{}
for _, w := range want {
wn = append(wn, w.PodName())
}
if len(unique) != len(wn) {
return fmt.Errorf("excepted all destinations (%v), got: %v", wn, unique)
}
return nil
}

shouldBalance := dst.Config().HasServiceAddressedWaypointProxy()
// Istio client will not reuse connections for HTTP/1.1
opt.HTTP.HTTP2 = true
// Make sure we make multiple calls
opt.Count = 10
c := singleHost
if shouldBalance {
c = multipleHost
}
opt.Check = check.And(check.OK(), c)
opt.NewConnectionPerRequest = false
src.CallOrFail(t, opt)
})
})
}

func TestServerRouting(t *testing.T) {
framework.NewTest(t).Run(func(t framework.TestContext) {
runTestToServiceWaypoint(t, func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions) {
// Need waypoint proxy and HTTP
if opt.Scheme != scheme.HTTP {
return
}
t.NewSubTest("set header").Run(func(t framework.TestContext) {
t.ConfigIstio().Eval(apps.Namespace.Name(), map[string]string{
"Destination": dst.Config().Service,
}, `apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: route
spec:
hosts:
- "{{.Destination}}"
http:
- headers:
request:
add:
kmesh-custom-header: user-defined-value
route:
- destination:
host: "{{.Destination}}"
`).ApplyOrFail(t)
opt.Check = check.And(
check.OK(),
check.RequestHeader("Kmesh-Custom-Header", "user-defined-value"))
src.CallOrFail(t, opt)
})
t.NewSubTest("route to a specific subnet").Run(func(t framework.TestContext) {
t.ConfigIstio().Eval(apps.Namespace.Name(), map[string]string{
"Destination": dst.Config().Service,
}, `apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: route
spec:
hosts:
- "{{.Destination}}"
http:
- route:
- destination:
host: "{{.Destination}}"
subset: v1
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: route
namespace:
spec:
host: "{{.Destination}}"
subsets:
- labels:
version: v1
name: v1
- labels:
version: v2
name: v2
`).ApplyOrFail(t)
var exp string
for _, w := range dst.WorkloadsOrFail(t) {
if strings.Contains(w.PodName(), "-v1") {
exp = w.PodName()
}
}
opt.Count = 10
opt.Check = check.And(
check.OK(),
check.Hostname(exp))
src.CallOrFail(t, opt)
})
})
})
}

func TestWaypointEnvoyFilter(t *testing.T) {
framework.NewTest(t).Run(func(t framework.TestContext) {
runTestToServiceWaypoint(t, func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions) {
// Need at least one waypoint proxy and HTTP
if opt.Scheme != scheme.HTTP {
return
}
t.ConfigIstio().Eval(apps.Namespace.Name(), map[string]string{
"Destination": "waypoint",
}, `apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: inbound
spec:
workloadSelector:
labels:
gateway.networking.k8s.io/gateway-name: "{{.Destination}}"
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle)
request_handle:headers():add("x-lua-inbound", "hello world")
end
- applyTo: VIRTUAL_HOST
match:
context: SIDECAR_INBOUND
patch:
operation: MERGE
value:
request_headers_to_add:
- header:
key: x-vhost-inbound
value: "hello world"
- applyTo: CLUSTER
match:
context: SIDECAR_INBOUND
cluster: {}
patch:
operation: MERGE
value:
http2_protocol_options: {}
`).ApplyOrFail(t)
opt.Count = 5
opt.Timeout = time.Second * 10
opt.Check = check.And(
check.OK(),
check.RequestHeaders(map[string]string{
"X-Lua-Inbound": "hello world",
"X-Vhost-Inbound": "hello world",
}))
src.CallOrFail(t, opt)
})
})
Expand All @@ -144,6 +348,24 @@ func runTest(t *testing.T, f func(t framework.TestContext, src echo.Instance, ds
})
}

// runTestToServiceWaypoint runs a given function against every src/dst pair where a call will traverse a service waypoint
func runTestToServiceWaypoint(t framework.TestContext, f func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions)) {
runTestContext(t, func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions) {
if !dst.Config().HasServiceAddressedWaypointProxy() {
return
}
if !src.Config().HasProxyCapabilities() {
// Only respected if the client knows about waypoints
return
}
if src.Config().HasSidecar() {
// TODO: sidecars do not currently respect waypoints
t.Skip("https://github.com/istio/istio/issues/51445")
}
f(t, src, dst, opt)
})
}

func runTestContext(t framework.TestContext, f func(t framework.TestContext, src echo.Instance, dst echo.Instance, opt echo.CallOptions)) {
svcs := apps.All
for _, src := range svcs {
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
* limitations under the License.
*/

// NOTE: THE CODE IN THIS FILE IS MAINLY REFERENCED FROM ISTIO INTEGRATION
// FRAMEWORK(https://github.com/istio/istio/tree/master/tests/integration)
// AND ADAPTED FOR KMESH.

package kmesh

import (
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/run_test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/bash

# NOTE: Kmesh e2e test framework is heavily inspired by istio integration
# framework (https://github.com/istio/istio/tree/master/tests/integration),
# both in architecture and code.
# NOTE: THE CODE IN THIS FILE IS MAINLY REFERENCED FROM ISTIO INTEGRATION
# FRAMEWORK(https://github.com/istio/istio/tree/master/tests/integration)
# AND ADAPTED FOR KMESH.

# Exit immediately for non zero status
set -e
Expand Down

0 comments on commit 781fc97

Please sign in to comment.