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

Fixes for mesh conformance tests #2017

Merged
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
2 changes: 1 addition & 1 deletion conformance/tests/mesh-split.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var MeshTrafficSplit = suite.ConformanceTest{
// reuse issues across parallel tests.
tc := cases[i]
t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
client.SendRequest(t, tc)
client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
})
}
},
Expand Down
78 changes: 55 additions & 23 deletions conformance/utils/echo/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ import (
"fmt"
"strings"
"testing"
"time"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
klabels "k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"sigs.k8s.io/controller-runtime/pkg/client"

"sigs.k8s.io/gateway-api/conformance/utils/config"
"sigs.k8s.io/gateway-api/conformance/utils/http"
"sigs.k8s.io/gateway-api/conformance/utils/suite"
)
Expand All @@ -40,6 +41,7 @@ import (
type MeshPod struct {
Name string
Namespace string
Address string
rc *rest.RESTClient
rcfg *rest.Config
}
Expand All @@ -51,42 +53,73 @@ const (
MeshAppEchoV2 MeshApplication = "app=echo,version=v2"
)

func (m *MeshPod) SendRequest(t *testing.T, exp http.ExpectedResponse) {
r := exp.Request
func (m *MeshPod) MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, exp http.ExpectedResponse, timeoutConfig config.TimeoutConfig) {
t.Helper()

req := makeRequest(exp.Request)

http.AwaitConvergence(t, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency, func(elapsed time.Duration) bool {
resp, err := m.request(makeRequest(exp.Request))
if err != nil {
t.Logf("Request failed, not ready yet: %v (after %v)", err.Error(), elapsed)
return false
}
t.Logf("Got resp %v", resp)
if err := compareRequest(exp, resp); err != nil {
t.Logf("Response expectation failed for request: %v not ready yet: %v (after %v)", req, err, elapsed)
return false
}
return true
})

t.Logf("Request passed")
}

func makeRequest(r http.Request) []string {
protocol := strings.ToLower(r.Protocol)
if protocol == "" {
protocol = "http"
}
args := []string{"client", fmt.Sprintf("%s://%s/%s", protocol, r.Host, r.Path)}
args := []string{"client", fmt.Sprintf("%s://%s%s", protocol, r.Host, r.Path)}
if r.Method != "" {
args = append(args, "--method="+r.Method)
}
if !r.UnfollowRedirect {
args = append(args, "--follow-redirects")
}
for k, v := range r.Headers {
args = append(args, "-H", fmt.Sprintf("%v: %v", k, v))
}
return args
}

resp, err := m.request(args)
func (m *MeshPod) SendRequest(t *testing.T, exp http.ExpectedResponse) {
resp, err := m.request(makeRequest(exp.Request))
if err != nil {
t.Fatalf("Got error: %v", err)
}
t.Logf("Got resp %v", resp)
if err := compareRequest(exp, resp); err != nil {
t.Fatalf("expectations failed: %v", err)
}
}

func compareRequest(exp http.ExpectedResponse, resp Response) error {
want := exp.Response
if fmt.Sprint(want.StatusCode) != resp.Code {
t.Errorf("wanted status code %v, got %v", want.StatusCode, resp.Code)
return fmt.Errorf("wanted status code %v, got %v", want.StatusCode, resp.Code)
}
for _, name := range want.AbsentHeaders {
if v := resp.ResponseHeaders.Values(name); len(v) != 0 {
t.Errorf("expected no header %q, got %v", name, v)
return fmt.Errorf("expected no header %q, got %v", name, v)
}
}
for k, v := range want.Headers {
if got := resp.RequestHeaders.Get(k); got != v {
t.Errorf("expected header %v=%v, got %v", k, v, got)
if got := resp.ResponseHeaders.Get(k); got != v {
return fmt.Errorf("expected header %v=%v, got %v", k, v, got)
}
}
if !strings.HasPrefix(resp.Hostname, exp.Backend) {
return fmt.Errorf("expected pod name to start with %s, got %s", exp.Backend, resp.Hostname)
}
return nil
}

func (m *MeshPod) request(args []string) (Response, error) {
Expand Down Expand Up @@ -129,26 +162,25 @@ func (m *MeshPod) request(args []string) (Response, error) {
func ConnectToApp(t *testing.T, s *suite.ConformanceTestSuite, app MeshApplication) MeshPod {
// hardcoded, for now
ns := "gateway-conformance-mesh"
metaList := &metav1.PartialObjectMetadataList{}
metaList.SetGroupVersionKind(schema.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "PodList",
})

err := s.Client.List(context.Background(), metaList, client.InNamespace(ns), client.HasLabels(strings.Split(string(app), ",")))
lbls, _ := klabels.Parse(string(app))

podsList := v1.PodList{}
err := s.Client.List(context.Background(), &podsList, client.InNamespace(ns), client.MatchingLabelsSelector{Selector: lbls})
if err != nil {
t.Fatalf("failed to query pods in app %v", app)
}
if len(metaList.Items) == 0 {
if len(podsList.Items) == 0 {
t.Fatalf("no pods found in app %v", app)
}
podName := metaList.Items[0].Name
podNamespace := metaList.Items[0].Namespace
pod := podsList.Items[0]
podName := pod.Name
podNamespace := pod.Namespace

return MeshPod{
Name: podName,
Namespace: podNamespace,
Address: pod.Status.PodIP,
rc: s.RESTClient,
rcfg: s.RestConfig,
}
Expand Down