...

Source file src/goji.io/router_test.go

Documentation: goji.io

     1  package goji
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"goji.io/internal"
    10  	"goji.io/pattern"
    11  )
    12  
    13  func TestNoMatch(t *testing.T) {
    14  	t.Parallel()
    15  
    16  	var rt router
    17  	rt.add(boolPattern(false), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    18  		t.Fatal("did not expect handler to be called")
    19  	}))
    20  	_, r := wr()
    21  	ctx := context.Background()
    22  	ctx = context.WithValue(ctx, internal.Pattern, boolPattern(true))
    23  	ctx = context.WithValue(ctx, internal.Pattern, boolPattern(true))
    24  	ctx = context.WithValue(ctx, pattern.Variable("answer"), 42)
    25  	ctx = context.WithValue(ctx, internal.Path, "/")
    26  
    27  	r = r.WithContext(ctx)
    28  	r = rt.route(r)
    29  	ctx = r.Context()
    30  
    31  	if p := ctx.Value(internal.Pattern); p != nil {
    32  		t.Errorf("unexpected pattern %v", p)
    33  	}
    34  	if h := ctx.Value(internal.Handler); h != nil {
    35  		t.Errorf("unexpected handler %v", h)
    36  	}
    37  	if h := ctx.Value(pattern.Variable("answer")); h != 42 {
    38  		t.Errorf("context didn't work: got %v, wanted %v", h, 42)
    39  	}
    40  }
    41  
    42  /*
    43  These are meant to be end-to-end torture tests of Goji's routing semantics. We
    44  generate a list of patterns that can be turned off incrementally with a global
    45  "high water mark." We then run a sequence of requests through the router N
    46  times, incrementing the mark each time. The net effect is that we can compile
    47  the entire set of routes Goji would attempt for every request, ensuring that the
    48  router is picking routes in the correct order.
    49  */
    50  
    51  var TestRoutes = []testPattern{
    52  	testPattern{methods: nil, prefix: "/"},
    53  	testPattern{methods: nil, prefix: "/a"},
    54  	testPattern{methods: []string{"POST", "PUT"}, prefix: "/a"},
    55  	testPattern{methods: []string{"GET", "POST"}, prefix: "/a"},
    56  	testPattern{methods: []string{"GET"}, prefix: "/b"},
    57  	testPattern{methods: nil, prefix: "/ab"},
    58  	testPattern{methods: []string{"POST", "PUT"}, prefix: "/"},
    59  	testPattern{methods: nil, prefix: "/ba"},
    60  	testPattern{methods: nil, prefix: "/"},
    61  	testPattern{methods: []string{}, prefix: "/"},
    62  	testPattern{methods: nil, prefix: "/carl"},
    63  	testPattern{methods: []string{"PUT"}, prefix: "/car"},
    64  	testPattern{methods: nil, prefix: "/cake"},
    65  	testPattern{methods: nil, prefix: "/car"},
    66  	testPattern{methods: []string{"GET"}, prefix: "/c"},
    67  	testPattern{methods: []string{"POST"}, prefix: "/"},
    68  	testPattern{methods: []string{"PUT"}, prefix: "/"},
    69  }
    70  
    71  var RouterTests = []struct {
    72  	method, path string
    73  	results      []int
    74  }{
    75  	{"GET", "/", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    76  	{"POST", "/", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
    77  	{"PUT", "/", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16}},
    78  	{"HEAD", "/", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    79  	{"GET", "/a", []int{0, 1, 3, 3, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    80  	{"POST", "/a", []int{0, 1, 2, 3, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
    81  	{"PUT", "/a", []int{0, 1, 2, 6, 6, 6, 6, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16}},
    82  	{"HEAD", "/a", []int{0, 1, 8, 8, 8, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    83  	{"GET", "/b", []int{0, 4, 4, 4, 4, 8, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    84  	{"POST", "/b", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
    85  	{"GET", "/ba", []int{0, 4, 4, 4, 4, 7, 7, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    86  	{"GET", "/c", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 14, 14, 14, 14, 14, 14, -1, -1}},
    87  	{"POST", "/c", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
    88  	{"GET", "/ab", []int{0, 1, 3, 3, 5, 5, 8, 8, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
    89  	{"POST", "/ab", []int{0, 1, 2, 3, 5, 5, 6, 8, 8, 15, 15, 15, 15, 15, 15, 15, -1}},
    90  	{"GET", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, 14, -1, -1}},
    91  	{"POST", "/carl", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 10, 10, 13, 13, 13, 15, 15, -1}},
    92  	{"HEAD", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, -1, -1, -1}},
    93  	{"PUT", "/carl", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 10, 10, 11, 13, 13, 16, 16, 16}},
    94  	{"GET", "/cake", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 14, 14, -1, -1}},
    95  	{"PUT", "/cake", []int{0, 6, 6, 6, 6, 6, 6, 8, 8, 12, 12, 12, 12, 16, 16, 16, 16}},
    96  	{"OHAI", "/carl", []int{0, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 13, 13, 13, -1, -1, -1}},
    97  }
    98  
    99  func TestRouter(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	var rt router
   103  	mark := new(int)
   104  	for i, p := range TestRoutes {
   105  		i := i
   106  		p.index = i
   107  		p.mark = mark
   108  		rt.add(p, intHandler(i))
   109  	}
   110  
   111  	for i, test := range RouterTests {
   112  		r, err := http.NewRequest(test.method, test.path, nil)
   113  		if err != nil {
   114  			panic(err)
   115  		}
   116  		ctx := context.WithValue(context.Background(), internal.Path, test.path)
   117  		r = r.WithContext(ctx)
   118  
   119  		var out []int
   120  		for *mark = 0; *mark < len(TestRoutes); *mark++ {
   121  			r := rt.route(r)
   122  			ctx := r.Context()
   123  			if h := ctx.Value(internal.Handler); h != nil {
   124  				out = append(out, int(h.(intHandler)))
   125  			} else {
   126  				out = append(out, -1)
   127  			}
   128  		}
   129  		if !reflect.DeepEqual(out, test.results) {
   130  			t.Errorf("[%d] expected %v got %v", i, test.results, out)
   131  		}
   132  	}
   133  }
   134  
   135  type contextPattern struct{}
   136  
   137  func (contextPattern) Match(r *http.Request) *http.Request {
   138  	return r.WithContext(context.WithValue(r.Context(), pattern.Variable("hello"), "world"))
   139  }
   140  
   141  func TestRouterContextPropagation(t *testing.T) {
   142  	t.Parallel()
   143  
   144  	var rt router
   145  	rt.add(contextPattern{}, intHandler(0))
   146  	_, r := wr()
   147  	r = r.WithContext(context.WithValue(r.Context(), internal.Path, "/"))
   148  	r2 := rt.route(r)
   149  	ctx := r2.Context()
   150  	if hello := ctx.Value(pattern.Variable("hello")).(string); hello != "world" {
   151  		t.Fatalf("routed request didn't include correct key from pattern: %q", hello)
   152  	}
   153  }
   154  

View as plain text