...
1 package testutil
2
3 import (
4 "fmt"
5 "strings"
6 "time"
7 )
8
9
10 type TapEvent struct {
11 Method string
12 Authority string
13 Path string
14 HTTPStatus string
15 GrpcStatus string
16 TLS string
17 LineCount int
18 }
19
20
21
22 func Tap(target string, h *TestHelper, arg ...string) ([]*TapEvent, error) {
23 cmd := append([]string{"viz", "tap", target}, arg...)
24 outputStream, err := h.LinkerdRunStream(cmd...)
25 if err != nil {
26 return nil, err
27 }
28 defer outputStream.Stop()
29
30 outputLines, err := outputStream.ReadUntil(10, 1*time.Minute)
31 if err != nil {
32 return nil, err
33 }
34
35 tapEventByID := make(map[string]*TapEvent)
36 for _, line := range outputLines {
37 fields := toFieldMap(line)
38 obj, ok := tapEventByID[fields["id"]]
39 if !ok {
40 obj = &TapEvent{}
41 tapEventByID[fields["id"]] = obj
42 }
43 obj.LineCount++
44 obj.TLS = fields["tls"]
45
46 switch fields["type"] {
47 case "req":
48 obj.Method = fields[":method"]
49 obj.Authority = fields[":authority"]
50 obj.Path = fields[":path"]
51 case "rsp":
52 obj.HTTPStatus = fields[":status"]
53 case "end":
54 obj.GrpcStatus = fields["grpc-status"]
55 }
56 }
57
58 output := make([]*TapEvent, 0)
59 for _, obj := range tapEventByID {
60 if obj.LineCount == 3 {
61 output = append(output, obj)
62 }
63 }
64
65 return output, nil
66 }
67
68 func toFieldMap(line string) map[string]string {
69 fields := strings.Fields(line)
70 fieldMap := map[string]string{"type": fields[0]}
71 for _, field := range fields[1:] {
72 parts := strings.SplitN(field, "=", 2)
73 fieldMap[parts[0]] = parts[1]
74 }
75 return fieldMap
76 }
77
78
79 func ValidateExpected(events []*TapEvent, expectedEvent TapEvent) error {
80 if len(events) == 0 {
81 return fmt.Errorf("Expected tap events, got nothing")
82 }
83 for _, event := range events {
84 if *event != expectedEvent {
85 return fmt.Errorf("Unexpected tap event [%+v]; expected=[%+v]", *event, expectedEvent)
86 }
87 }
88 return nil
89 }
90
View as plain text