github.com/shogo82148/goa-v1@v1.6.2/context_test.go (about)

     1  package goa_test
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/url"
     7  	"time"
     8  
     9  	. "github.com/onsi/ginkgo"
    10  	. "github.com/onsi/gomega"
    11  	"github.com/shogo82148/goa-v1"
    12  )
    13  
    14  // contextKey is a value for use with context.WithValue. It's used as
    15  // a pointer so it fits in an interface{} without allocation.
    16  type contextKey struct {
    17  	name string
    18  }
    19  
    20  func (k *contextKey) String() string { return "goa-v1 context value " + k.name }
    21  
    22  var _ = Describe("ResponseData", func() {
    23  	var data *goa.ResponseData
    24  	var rw http.ResponseWriter
    25  	var req *http.Request
    26  	var params url.Values
    27  
    28  	BeforeEach(func() {
    29  		var err error
    30  		req, err = http.NewRequest("GET", "google.com", nil)
    31  		Ω(err).ShouldNot(HaveOccurred())
    32  		rw = &TestResponseWriter{Status: 42}
    33  		params = url.Values{"query": []string{"value"}}
    34  		ctx := goa.NewContext(context.Background(), rw, req, params)
    35  		data = goa.ContextResponse(ctx)
    36  	})
    37  
    38  	Context("SwitchWriter", func() {
    39  		var rwo http.ResponseWriter
    40  
    41  		It("sets the response writer and returns the previous one", func() {
    42  			Ω(rwo).Should(BeNil())
    43  			rwo = data.SwitchWriter(&TestResponseWriter{Status: 43})
    44  			Ω(rwo).ShouldNot(BeNil())
    45  			Ω(rwo).Should(BeAssignableToTypeOf(&TestResponseWriter{}))
    46  			trw := rwo.(*TestResponseWriter)
    47  			Ω(trw.Status).Should(Equal(42))
    48  		})
    49  	})
    50  
    51  	Context("Write", func() {
    52  		It("should call WriteHeader(http.StatusOK) if WriteHeader has not yet been called", func() {
    53  			_, err := data.Write(nil)
    54  			Ω(err).Should(BeNil())
    55  			Ω(data.Status).Should(Equal(http.StatusOK))
    56  		})
    57  
    58  		It("should not affect Status if WriteHeader has been called", func() {
    59  			status := http.StatusBadRequest
    60  			data.WriteHeader(status)
    61  			_, err := data.Write(nil)
    62  			Ω(err).Should(BeNil())
    63  			Ω(data.Status).Should(Equal(status))
    64  		})
    65  	})
    66  
    67  	Context("Context", func() {
    68  		mergeContext := func(parent, child context.Context) context.Context {
    69  			req, err := http.NewRequestWithContext(child, "GET", "google.com", nil)
    70  			Ω(err).Should(BeNil())
    71  			return goa.NewContext(parent, &TestResponseWriter{Status: 42}, req, url.Values{})
    72  		}
    73  		Context("Deadline", func() {
    74  			It("should be empty if the parent and the child have no deadline", func() {
    75  				ctx := mergeContext(context.Background(), context.Background())
    76  				_, ok := ctx.Deadline()
    77  				Ω(ok).Should(Equal(false))
    78  			})
    79  			It("should return the parent's deadline if the child have no deadline", func() {
    80  				deadline := time.Now().Add(time.Second)
    81  				parent, cancel := context.WithDeadline(context.Background(), deadline)
    82  				defer cancel()
    83  				ctx := mergeContext(parent, context.Background())
    84  				got, ok := ctx.Deadline()
    85  				Ω(ok).Should(Equal(true))
    86  				Ω(got).Should(BeTemporally("~", deadline, 100*time.Millisecond))
    87  			})
    88  			It("should return the child's deadline if the parent have no deadline", func() {
    89  				deadline := time.Now().Add(time.Second)
    90  				child, cancel := context.WithDeadline(context.Background(), deadline)
    91  				defer cancel()
    92  				ctx := mergeContext(context.Background(), child)
    93  				got, ok := ctx.Deadline()
    94  				Ω(ok).Should(Equal(true))
    95  				Ω(got).Should(BeTemporally("~", deadline, 100*time.Millisecond))
    96  			})
    97  			It("should return the child's deadline if it is earlier than the parent's one", func() {
    98  				deadline1 := time.Now().Add(time.Second)
    99  				child, cancel := context.WithDeadline(context.Background(), deadline1)
   100  				defer cancel()
   101  				deadline2 := time.Now().Add(2 * time.Second)
   102  				parent, cancel := context.WithDeadline(context.Background(), deadline2)
   103  				defer cancel()
   104  
   105  				ctx := mergeContext(parent, child)
   106  				got, ok := ctx.Deadline()
   107  				Ω(ok).Should(Equal(true))
   108  				Ω(got).Should(BeTemporally("~", deadline1, 100*time.Millisecond))
   109  			})
   110  			It("should return the parent's deadline if it is earlier than the child's one", func() {
   111  				deadline1 := time.Now().Add(2 * time.Second)
   112  				child, cancel := context.WithDeadline(context.Background(), deadline1)
   113  				defer cancel()
   114  				deadline2 := time.Now().Add(time.Second)
   115  				parent, cancel := context.WithDeadline(context.Background(), deadline2)
   116  				defer cancel()
   117  
   118  				ctx := mergeContext(parent, child)
   119  				got, ok := ctx.Deadline()
   120  				Ω(ok).Should(Equal(true))
   121  				Ω(got).Should(BeTemporally("~", deadline2, 100*time.Millisecond))
   122  			})
   123  		})
   124  		Context("Done", func() {
   125  			It("should be canceled when the parent is canceled", func() {
   126  				deadline := time.Now().Add(time.Second)
   127  				parent, cancel := context.WithDeadline(context.Background(), deadline)
   128  				defer cancel()
   129  
   130  				ctx := mergeContext(parent, context.Background())
   131  				select {
   132  				case <-ctx.Done():
   133  				case <-time.After(5 * time.Second):
   134  					Fail("timeout")
   135  				}
   136  				Ω(ctx.Err()).ShouldNot(BeNil())
   137  				Ω(time.Now()).Should(BeTemporally("~", deadline, 500*time.Millisecond))
   138  			})
   139  			It("should be canceled when the child is canceled", func() {
   140  				deadline := time.Now().Add(time.Second)
   141  				child, cancel := context.WithDeadline(context.Background(), deadline)
   142  				defer cancel()
   143  
   144  				ctx := mergeContext(context.Background(), child)
   145  				select {
   146  				case <-ctx.Done():
   147  				case <-time.After(5 * time.Second):
   148  					Fail("timeout")
   149  				}
   150  				Ω(ctx.Err()).ShouldNot(BeNil())
   151  				Ω(time.Now()).Should(BeTemporally("~", deadline, 500*time.Millisecond))
   152  			})
   153  		})
   154  		Context("Value", func() {
   155  			key := &contextKey{"key"}
   156  			otherKey := &contextKey{"other-key"}
   157  			It("should return the value associated with the child if it exists", func() {
   158  				parent := context.WithValue(context.Background(), key, "parent value")
   159  				child := context.WithValue(context.Background(), key, "child value")
   160  				ctx := mergeContext(parent, child)
   161  				Ω(ctx.Value(key)).Should(Equal("child value"))
   162  			})
   163  			It("should return the value associated with the parent if the child associates nothing", func() {
   164  				parent := context.WithValue(context.Background(), key, "parent value")
   165  				child := context.WithValue(context.Background(), otherKey, "child value")
   166  				ctx := mergeContext(parent, child)
   167  				Ω(ctx.Value(key)).Should(Equal("parent value"))
   168  			})
   169  		})
   170  	})
   171  })