github.com/ManabuSeki/goa-v1@v1.4.3/middleware/xray/wrap_doer_test.go (about)

     1  package xray
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"net/http"
     8  	"strings"
     9  	"testing"
    10  
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/gstruct"
    13  )
    14  
    15  func TestWrapDoer(t *testing.T) {
    16  	RegisterTestingT(t)
    17  
    18  	var (
    19  		doer = NewMockDoer()
    20  		ctx  = context.Background()
    21  	)
    22  	req, err := http.NewRequest("GET", "http://somehost:80/path", nil)
    23  	Expect(err).To(Succeed())
    24  
    25  	t.Run(`no segment in context; success`, func(t *testing.T) {
    26  		RegisterTestingT(t)
    27  
    28  		doer.Expect("Do", func(c context.Context, r *http.Request) (*http.Response, error) {
    29  			Expect(r).To(Equal(req))
    30  			Expect(c).To(Equal(ctx))
    31  			return &http.Response{StatusCode: 123}, nil
    32  		})
    33  		resp, err := WrapDoer(doer).Do(ctx, req)
    34  		Expect(err).To(Succeed())
    35  		Expect(resp.StatusCode).To(Equal(123))
    36  		Expect(doer.MetExpectations()).To(Succeed())
    37  	})
    38  
    39  	const (
    40  		segmentName = "segmentName1"
    41  		traceID     = "traceID1"
    42  		spanID      = "spanID1"
    43  	)
    44  
    45  	t.Run(`with a segment in context - successful request`, func(t *testing.T) {
    46  		RegisterTestingT(t)
    47  
    48  		// add an xray segment to the context
    49  		xrayConn := NewTestNetConn()
    50  		segment := NewSegment(segmentName, traceID, spanID, xrayConn)
    51  		ctx = WithSegment(ctx, segment)
    52  
    53  		doer.Expect("Do", func(c context.Context, r *http.Request) (*http.Response, error) {
    54  			Expect(r).To(Equal(req))
    55  			Expect(ContextSegment(c).ParentID).To(Equal(segment.ID))
    56  			return &http.Response{StatusCode: 123}, nil
    57  		})
    58  
    59  		// "in_progress":true segment
    60  		xrayConn.Expect("Write", func(b []byte) (int, error) {
    61  			lines := strings.Split(string(b), "\n")
    62  			Expect(lines).To(HaveLen(2))
    63  			Expect(lines[0]).To(Equal(`{"format": "json", "version": 1}`))
    64  
    65  			var s Segment
    66  			Expect(json.Unmarshal([]byte(lines[1]), &s)).To(Succeed())
    67  			Expect(s).To(MatchFields(IgnoreExtras, Fields{
    68  				"Name":       Equal("somehost:80"),
    69  				"Type":       Equal("subsegment"),
    70  				"ID":         SatisfyAll(Not(BeEmpty()), Not(Equal(segment.ID))), // randomly generated
    71  				"TraceID":    Equal(traceID),
    72  				"ParentID":   Equal(spanID),
    73  				"InProgress": BeTrue(),
    74  			}))
    75  			return len(b), nil
    76  		})
    77  
    78  		// final "in_progress":false segment
    79  		xrayConn.Expect("Write", func(b []byte) (int, error) {
    80  			lines := strings.Split(string(b), "\n")
    81  			Expect(lines).To(HaveLen(2))
    82  			Expect(lines[0]).To(Equal(`{"format": "json", "version": 1}`))
    83  
    84  			var s Segment
    85  			err := json.Unmarshal([]byte(lines[1]), &s)
    86  			Expect(err).To(Succeed())
    87  			Expect(s).To(MatchFields(IgnoreExtras, Fields{
    88  				"Name":      Equal("somehost:80"),
    89  				"Namespace": Equal("remote"),
    90  				"Type":      Equal("subsegment"),
    91  				"ID":        And(Not(BeEmpty()), Not(Equal(segment.ID))), // randomly generated
    92  				"TraceID":   Equal(traceID),
    93  				"ParentID":  Equal(spanID),
    94  				"Error":     BeFalse(),
    95  				"HTTP": PointTo(MatchAllFields(Fields{
    96  					"Request":  Equal(&Request{Method: "GET", URL: "http://somehost:80/path"}),
    97  					"Response": Equal(&Response{Status: 123}),
    98  				})),
    99  				"InProgress": BeFalse(),
   100  			}))
   101  			return len(b), nil
   102  		})
   103  		resp, err := WrapDoer(doer).Do(ctx, req)
   104  		Expect(err).To(Succeed())
   105  		Expect(resp.StatusCode).To(Equal(123))
   106  		Expect(doer.MetExpectations()).To(Succeed())
   107  		Expect(xrayConn.MetExpectations()).To(Succeed())
   108  	})
   109  
   110  	t.Run(`with a segment in context - failed request`, func(t *testing.T) {
   111  		RegisterTestingT(t)
   112  
   113  		// add an xray segment to the context
   114  		xrayConn := NewTestNetConn()
   115  		segment := NewSegment(segmentName, traceID, spanID, xrayConn)
   116  		ctx = WithSegment(ctx, segment)
   117  
   118  		var (
   119  			requestErr = errors.New("some request error")
   120  		)
   121  		doer.Expect("Do", func(c context.Context, r *http.Request) (*http.Response, error) {
   122  			Expect(ContextSegment(c).ParentID).To(Equal(segment.ID))
   123  			return nil, requestErr
   124  		})
   125  
   126  		// "in_progress":true segment
   127  		xrayConn.Expect("Write", func(b []byte) (int, error) {
   128  			lines := strings.Split(string(b), "\n")
   129  			Expect(lines).To(HaveLen(2))
   130  			Expect(lines[0]).To(Equal(`{"format": "json", "version": 1}`))
   131  
   132  			var s Segment
   133  			Expect(json.Unmarshal([]byte(lines[1]), &s)).To(Succeed())
   134  			Expect(s).To(MatchFields(IgnoreExtras, Fields{
   135  				"Name":       Equal("somehost:80"),
   136  				"Type":       Equal("subsegment"),
   137  				"ID":         SatisfyAll(Not(BeEmpty()), Not(Equal(segment.ID))), // randomly generated
   138  				"TraceID":    Equal(traceID),
   139  				"ParentID":   Equal(spanID),
   140  				"InProgress": BeTrue(),
   141  			}))
   142  			return len(b), nil
   143  		})
   144  
   145  		// final "in_progress":false segment
   146  		xrayConn.Expect("Write", func(b []byte) (int, error) {
   147  			lines := strings.Split(string(b), "\n")
   148  			Expect(lines).To(HaveLen(2))
   149  			Expect(lines[0]).To(Equal(`{"format": "json", "version": 1}`))
   150  
   151  			var s Segment
   152  			err := json.Unmarshal([]byte(lines[1]), &s)
   153  			Expect(err).To(Succeed())
   154  			Expect(s).To(MatchFields(IgnoreExtras, Fields{
   155  				"Name":      Equal("somehost:80"),
   156  				"Namespace": Equal("remote"),
   157  				"Type":      Equal("subsegment"),
   158  				"ID":        And(Not(BeEmpty()), Not(Equal(segment.ID))), // randomly generated
   159  				"TraceID":   Equal(traceID),
   160  				"ParentID":  Equal(spanID),
   161  				"Error":     BeTrue(),
   162  				"HTTP": PointTo(MatchAllFields(Fields{
   163  					"Request":  Equal(&Request{Method: "GET", URL: "http://somehost:80/path"}),
   164  					"Response": BeNil(),
   165  				})),
   166  				"InProgress": BeFalse(),
   167  			}))
   168  			return len(b), nil
   169  		})
   170  		_, err := WrapDoer(doer).Do(ctx, req)
   171  		Expect(err).To(MatchError(requestErr))
   172  
   173  		Expect(doer.MetExpectations()).To(Succeed())
   174  		Expect(xrayConn.MetExpectations()).To(Succeed())
   175  	})
   176  }
   177  
   178  type MockDoer struct {
   179  	*TestClientExpectation
   180  }
   181  
   182  func NewMockDoer() *MockDoer {
   183  	return &MockDoer{NewTestClientExpectation()}
   184  }
   185  
   186  func (m *MockDoer) Do(ctx context.Context, req *http.Request) (*http.Response, error) {
   187  	if e := m.Expectation("Do"); e != nil {
   188  		return e.(func(context.Context, *http.Request) (*http.Response, error))(ctx, req)
   189  	}
   190  	return nil, nil
   191  }