...

Source file src/github.com/linkerd/linkerd2/testutil/tap.go

Documentation: github.com/linkerd/linkerd2/testutil

     1  package testutil
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  )
     8  
     9  // TapEvent represents a tap event
    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  // Tap executes a tap command and converts the command's streaming output into tap
    21  // events using each line's "id" field
    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 { // filter out incomplete events
    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  // ValidateExpected compares the received tap event with the expected tap event
    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