Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add some waypoint related E2E test cases #580

Merged
merged 3 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have workload level waypoint?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet, relevant test cases will be added later

}
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
Loading