github.com/rjeczalik/buffalo@v0.11.1/router_test.go (about)

     1  package buffalo
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"path"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/gobuffalo/buffalo/render"
    13  	"github.com/gobuffalo/packr"
    14  	"github.com/gorilla/mux"
    15  	"github.com/markbates/willie"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func testApp() *App {
    20  	a := New(Options{})
    21  	a.Redirect(301, "/foo", "/bar")
    22  	a.GET("/bar", func(c Context) error {
    23  		return c.Render(200, render.String("bar"))
    24  	})
    25  
    26  	rt := a.Group("/router/tests")
    27  
    28  	h := func(c Context) error {
    29  		return c.Render(200, render.String(c.Request().Method+"|"+c.Value("current_path").(string)))
    30  	}
    31  
    32  	rt.GET("/", h)
    33  	rt.POST("/", h)
    34  	rt.PUT("/", h)
    35  	rt.DELETE("/", h)
    36  	rt.OPTIONS("/", h)
    37  	rt.PATCH("/", h)
    38  	return a
    39  }
    40  
    41  func otherTestApp() *App {
    42  	a := New(Options{})
    43  	f := func(c Context) error {
    44  		req := c.Request()
    45  		return c.Render(200, render.String(req.Method+" - "+req.URL.String()))
    46  	}
    47  	a.GET("/foo", f)
    48  	a.POST("/bar", f)
    49  	a.DELETE("/baz/baz", f)
    50  	return a
    51  }
    52  
    53  func Test_Mount_Buffalo(t *testing.T) {
    54  	r := require.New(t)
    55  	a := testApp()
    56  	a.Mount("/admin", otherTestApp())
    57  
    58  	table := map[string]string{
    59  		"/foo":     "GET",
    60  		"/bar":     "POST",
    61  		"/baz/baz": "DELETE",
    62  	}
    63  	ts := httptest.NewServer(a)
    64  	defer ts.Close()
    65  
    66  	for u, m := range table {
    67  		p := fmt.Sprintf("%s/%s", ts.URL, path.Join("admin", u))
    68  		req, err := http.NewRequest(m, p, nil)
    69  		r.NoError(err)
    70  		res, err := http.DefaultClient.Do(req)
    71  		r.NoError(err)
    72  		b, _ := ioutil.ReadAll(res.Body)
    73  		r.Equal(fmt.Sprintf("%s - %s", m, u), string(b))
    74  	}
    75  }
    76  
    77  func Test_Mount_Buffalo_on_Group(t *testing.T) {
    78  	r := require.New(t)
    79  	a := testApp()
    80  	g := a.Group("/users")
    81  	g.Mount("/admin", otherTestApp())
    82  
    83  	table := map[string]string{
    84  		"/foo":     "GET",
    85  		"/bar":     "POST",
    86  		"/baz/baz": "DELETE",
    87  	}
    88  	ts := httptest.NewServer(a)
    89  	defer ts.Close()
    90  
    91  	for u, m := range table {
    92  		p := fmt.Sprintf("%s/%s", ts.URL, path.Join("users", "admin", u))
    93  		req, err := http.NewRequest(m, p, nil)
    94  		r.NoError(err)
    95  		res, err := http.DefaultClient.Do(req)
    96  		r.NoError(err)
    97  		b, _ := ioutil.ReadAll(res.Body)
    98  		r.Equal(fmt.Sprintf("%s - %s", m, u), string(b))
    99  	}
   100  }
   101  
   102  func muxer() http.Handler {
   103  	f := func(res http.ResponseWriter, req *http.Request) {
   104  		fmt.Fprintf(res, "%s - %s", req.Method, req.URL.String())
   105  	}
   106  	mux := mux.NewRouter()
   107  	mux.HandleFunc("/foo", f).Methods("GET")
   108  	mux.HandleFunc("/bar", f).Methods("POST")
   109  	mux.HandleFunc("/baz/baz", f).Methods("DELETE")
   110  	return mux
   111  }
   112  
   113  func Test_Mount_Handler(t *testing.T) {
   114  	r := require.New(t)
   115  	a := testApp()
   116  	a.Mount("/admin", muxer())
   117  
   118  	table := map[string]string{
   119  		"/foo":     "GET",
   120  		"/bar":     "POST",
   121  		"/baz/baz": "DELETE",
   122  	}
   123  	ts := httptest.NewServer(a)
   124  	defer ts.Close()
   125  
   126  	for u, m := range table {
   127  		p := fmt.Sprintf("%s/%s", ts.URL, path.Join("admin", u))
   128  		req, err := http.NewRequest(m, p, nil)
   129  		r.NoError(err)
   130  		res, err := http.DefaultClient.Do(req)
   131  		r.NoError(err)
   132  		b, _ := ioutil.ReadAll(res.Body)
   133  		r.Equal(fmt.Sprintf("%s - %s", m, u), string(b))
   134  	}
   135  }
   136  
   137  func Test_PreHandlers(t *testing.T) {
   138  	r := require.New(t)
   139  	a := testApp()
   140  	bh := func(c Context) error {
   141  		req := c.Request()
   142  		return c.Render(200, render.String(req.Method+"-"+req.URL.String()))
   143  	}
   144  	a.GET("/ph", bh)
   145  	a.POST("/ph", bh)
   146  	mh := func(res http.ResponseWriter, req *http.Request) {
   147  		if req.Method == "GET" {
   148  			res.WriteHeader(418)
   149  			res.Write([]byte("boo"))
   150  		}
   151  	}
   152  	a.PreHandlers = append(a.PreHandlers, http.HandlerFunc(mh))
   153  
   154  	ts := httptest.NewServer(a)
   155  	defer ts.Close()
   156  
   157  	table := []struct {
   158  		Code   int
   159  		Method string
   160  		Result string
   161  	}{
   162  		{Code: 418, Method: "GET", Result: "boo"},
   163  		{Code: 200, Method: "POST", Result: "POST-/ph"},
   164  	}
   165  
   166  	for _, v := range table {
   167  		req, err := http.NewRequest(v.Method, ts.URL+"/ph", nil)
   168  		r.NoError(err)
   169  		res, err := http.DefaultClient.Do(req)
   170  		r.NoError(err)
   171  		b, err := ioutil.ReadAll(res.Body)
   172  		r.NoError(err)
   173  		r.Equal(v.Code, res.StatusCode)
   174  		r.Equal(v.Result, string(b))
   175  	}
   176  }
   177  
   178  func Test_PreWares(t *testing.T) {
   179  	r := require.New(t)
   180  	a := testApp()
   181  	bh := func(c Context) error {
   182  		req := c.Request()
   183  		return c.Render(200, render.String(req.Method+"-"+req.URL.String()))
   184  	}
   185  	a.GET("/ph", bh)
   186  	a.POST("/ph", bh)
   187  
   188  	mh := func(h http.Handler) http.Handler {
   189  		return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
   190  			if req.Method == "GET" {
   191  				res.WriteHeader(418)
   192  				res.Write([]byte("boo"))
   193  			}
   194  		})
   195  	}
   196  
   197  	a.PreWares = append(a.PreWares, mh)
   198  
   199  	ts := httptest.NewServer(a)
   200  	defer ts.Close()
   201  
   202  	table := []struct {
   203  		Code   int
   204  		Method string
   205  		Result string
   206  	}{
   207  		{Code: 418, Method: "GET", Result: "boo"},
   208  		{Code: 200, Method: "POST", Result: "POST-/ph"},
   209  	}
   210  
   211  	for _, v := range table {
   212  		req, err := http.NewRequest(v.Method, ts.URL+"/ph", nil)
   213  		r.NoError(err)
   214  		res, err := http.DefaultClient.Do(req)
   215  		r.NoError(err)
   216  		b, err := ioutil.ReadAll(res.Body)
   217  		r.NoError(err)
   218  		r.Equal(v.Code, res.StatusCode)
   219  		r.Equal(v.Result, string(b))
   220  	}
   221  }
   222  
   223  func Test_Router(t *testing.T) {
   224  	r := require.New(t)
   225  
   226  	table := []string{
   227  		"GET",
   228  		"POST",
   229  		"PUT",
   230  		"DELETE",
   231  		"OPTIONS",
   232  		"PATCH",
   233  	}
   234  
   235  	ts := httptest.NewServer(testApp())
   236  	defer ts.Close()
   237  
   238  	for _, v := range table {
   239  		req, err := http.NewRequest(v, fmt.Sprintf("%s/router/tests", ts.URL), nil)
   240  		r.NoError(err)
   241  		res, err := http.DefaultClient.Do(req)
   242  		r.NoError(err)
   243  		b, _ := ioutil.ReadAll(res.Body)
   244  		r.Equal(fmt.Sprintf("%s|/router/tests", v), string(b))
   245  	}
   246  }
   247  
   248  func Test_Router_Group(t *testing.T) {
   249  	r := require.New(t)
   250  
   251  	a := testApp()
   252  	g := a.Group("/api/v1")
   253  	g.GET("/users", func(c Context) error {
   254  		return c.Render(201, nil)
   255  	})
   256  
   257  	w := willie.New(a)
   258  	res := w.Request("/api/v1/users").Get()
   259  	r.Equal(201, res.Code)
   260  }
   261  
   262  func Test_Router_Group_on_Group(t *testing.T) {
   263  	r := require.New(t)
   264  
   265  	a := testApp()
   266  	g := a.Group("/api/v1")
   267  	g.GET("/users", func(c Context) error {
   268  		return c.Render(201, nil)
   269  	})
   270  	f := g.Group("/foo")
   271  	f.GET("/bar", func(c Context) error {
   272  		return c.Render(420, nil)
   273  	})
   274  
   275  	w := willie.New(a)
   276  	res := w.Request("/api/v1/foo/bar").Get()
   277  	r.Equal(420, res.Code)
   278  }
   279  
   280  func Test_Router_Group_Middleware(t *testing.T) {
   281  	r := require.New(t)
   282  
   283  	a := testApp()
   284  	a.Use(func(h Handler) Handler { return h })
   285  	r.Len(a.Middleware.stack, 4)
   286  
   287  	g := a.Group("/api/v1")
   288  	r.Len(a.Middleware.stack, 4)
   289  	r.Len(g.Middleware.stack, 4)
   290  
   291  	g.Use(func(h Handler) Handler { return h })
   292  	r.Len(a.Middleware.stack, 4)
   293  	r.Len(g.Middleware.stack, 5)
   294  }
   295  
   296  func Test_Router_Redirect(t *testing.T) {
   297  	r := require.New(t)
   298  	w := willie.New(testApp())
   299  	res := w.Request("/foo").Get()
   300  	r.Equal(301, res.Code)
   301  	r.Equal("/bar", res.Location())
   302  }
   303  
   304  func Test_Router_ServeFiles(t *testing.T) {
   305  	r := require.New(t)
   306  
   307  	tmpFile, err := ioutil.TempFile("", "assets")
   308  	r.NoError(err)
   309  
   310  	af := []byte("hi")
   311  	_, err = tmpFile.Write(af)
   312  	r.NoError(err)
   313  
   314  	a := New(Options{})
   315  	a.ServeFiles("/assets", http.Dir(filepath.Dir(tmpFile.Name())))
   316  
   317  	w := willie.New(a)
   318  	res := w.Request("/assets/%s", filepath.Base(tmpFile.Name())).Get()
   319  
   320  	r.Equal(200, res.Code)
   321  	r.Equal(af, res.Body.Bytes())
   322  }
   323  
   324  func Test_App_NamedRoutes(t *testing.T) {
   325  
   326  	type CarsResource struct {
   327  		*BaseResource
   328  	}
   329  
   330  	r := require.New(t)
   331  	a := New(Options{})
   332  
   333  	var carsResource Resource
   334  	carsResource = CarsResource{&BaseResource{}}
   335  
   336  	rr := render.New(render.Options{
   337  		HTMLLayout:   "application.html",
   338  		TemplatesBox: packr.NewBox("../templates"),
   339  		Helpers:      map[string]interface{}{},
   340  	})
   341  
   342  	sampleHandler := func(c Context) error {
   343  		c.Set("opts", map[string]interface{}{})
   344  		return c.Render(200, rr.String(`
   345  			1. <%= rootPath() %>
   346  			2. <%= usersPath() %>
   347  			3. <%= userPath({user_id: 1}) %>
   348  			4. <%= myPeepsPath() %>
   349  			5. <%= userPath(opts) %>
   350  			6. <%= carPath({car_id: 1}) %>
   351  			7. <%= newCarPath() %>
   352  			8. <%= editCarPath({car_id: 1}) %>
   353  			9. <%= editCarPath({car_id: 1, other: 12}) %>
   354  			10. <%= rootPath({"some":"variable","other": 12}) %>
   355  			11. <%= rootPath() %>
   356  			12. <%= rootPath({"special/":"12=ss"}) %>
   357  		`))
   358  	}
   359  
   360  	a.GET("/", sampleHandler)
   361  	a.GET("/users", sampleHandler)
   362  	a.GET("/users/{user_id}", sampleHandler)
   363  	a.GET("/peeps", sampleHandler).Name("myPeeps")
   364  	a.Resource("/car", carsResource)
   365  
   366  	w := willie.New(a)
   367  	res := w.Request("/").Get()
   368  
   369  	r.Equal(200, res.Code)
   370  	r.Contains(res.Body.String(), "1. /")
   371  	r.Contains(res.Body.String(), "2. /users")
   372  	r.Contains(res.Body.String(), "3. /users/1")
   373  	r.Contains(res.Body.String(), "4. /peeps")
   374  	r.Contains(res.Body.String(), "5. /users/{user_id}")
   375  	r.Contains(res.Body.String(), "6. /car/1")
   376  	r.Contains(res.Body.String(), "7. /car/new")
   377  	r.Contains(res.Body.String(), "8. /car/1/edit")
   378  	r.Contains(res.Body.String(), "9. /car/1/edit?other=12")
   379  	r.Contains(res.Body.String(), "10. /?other=12&some=variable")
   380  	r.Contains(res.Body.String(), "11. /")
   381  	r.Contains(res.Body.String(), "12. /?special%2F=12%3Dss")
   382  }
   383  
   384  func Test_Resource(t *testing.T) {
   385  	r := require.New(t)
   386  
   387  	type trs struct {
   388  		Method string
   389  		Path   string
   390  		Result string
   391  	}
   392  
   393  	tests := []trs{
   394  		{
   395  			Method: "GET",
   396  			Path:   "",
   397  			Result: "list",
   398  		},
   399  		{
   400  			Method: "GET",
   401  			Path:   "/new",
   402  			Result: "new",
   403  		},
   404  		{
   405  			Method: "GET",
   406  			Path:   "/1",
   407  			Result: "show 1",
   408  		},
   409  		{
   410  			Method: "GET",
   411  			Path:   "/1/edit",
   412  			Result: "edit 1",
   413  		},
   414  		{
   415  			Method: "POST",
   416  			Path:   "",
   417  			Result: "create",
   418  		},
   419  		{
   420  			Method: "PUT",
   421  			Path:   "/1",
   422  			Result: "update 1",
   423  		},
   424  		{
   425  			Method: "DELETE",
   426  			Path:   "/1",
   427  			Result: "destroy 1",
   428  		},
   429  	}
   430  
   431  	a := New(Options{})
   432  	a.Resource("/users", &userResource{})
   433  	a.Resource("/api/v1/users", &userResource{})
   434  
   435  	ts := httptest.NewServer(a)
   436  	defer ts.Close()
   437  
   438  	c := http.Client{}
   439  	for _, path := range []string{"/users", "/api/v1/users"} {
   440  		for _, test := range tests {
   441  			u := ts.URL + path + test.Path
   442  			req, err := http.NewRequest(test.Method, u, nil)
   443  			r.NoError(err)
   444  			res, err := c.Do(req)
   445  			r.NoError(err)
   446  			b, err := ioutil.ReadAll(res.Body)
   447  			r.NoError(err)
   448  			r.Equal(test.Result, string(b))
   449  		}
   450  	}
   451  
   452  }
   453  
   454  type userResource struct{}
   455  
   456  func (u *userResource) List(c Context) error {
   457  	return c.Render(200, render.String("list"))
   458  }
   459  
   460  func (u *userResource) Show(c Context) error {
   461  	return c.Render(200, render.String(`show <%=params["user_id"] %>`))
   462  }
   463  
   464  func (u *userResource) New(c Context) error {
   465  	return c.Render(200, render.String("new"))
   466  }
   467  
   468  func (u *userResource) Create(c Context) error {
   469  	return c.Render(200, render.String("create"))
   470  }
   471  
   472  func (u *userResource) Edit(c Context) error {
   473  	return c.Render(200, render.String(`edit <%=params["user_id"] %>`))
   474  }
   475  
   476  func (u *userResource) Update(c Context) error {
   477  	return c.Render(200, render.String(`update <%=params["user_id"] %>`))
   478  }
   479  
   480  func (u *userResource) Destroy(c Context) error {
   481  	return c.Render(200, render.String(`destroy <%=params["user_id"] %>`))
   482  }
   483  
   484  func Test_ResourceOnResource(t *testing.T) {
   485  	r := require.New(t)
   486  
   487  	a := New(Options{})
   488  	ur := a.Resource("/users", &userResource{})
   489  	ur.Resource("/people", &userResource{})
   490  
   491  	ts := httptest.NewServer(a)
   492  	defer ts.Close()
   493  
   494  	type trs struct {
   495  		Method string
   496  		Path   string
   497  		Result string
   498  	}
   499  	tests := []trs{
   500  		{
   501  			Method: "GET",
   502  			Path:   "/people",
   503  			Result: "list",
   504  		},
   505  		{
   506  			Method: "GET",
   507  			Path:   "/people/new",
   508  			Result: "new",
   509  		},
   510  		{
   511  			Method: "GET",
   512  			Path:   "/people/1",
   513  			Result: "show 1",
   514  		},
   515  		{
   516  			Method: "GET",
   517  			Path:   "/people/1/edit",
   518  			Result: "edit 1",
   519  		},
   520  		{
   521  			Method: "POST",
   522  			Path:   "/people",
   523  			Result: "create",
   524  		},
   525  		{
   526  			Method: "PUT",
   527  			Path:   "/people/1",
   528  			Result: "update 1",
   529  		},
   530  		{
   531  			Method: "DELETE",
   532  			Path:   "/people/1",
   533  			Result: "destroy 1",
   534  		},
   535  	}
   536  	c := http.Client{}
   537  	for _, test := range tests {
   538  		u := ts.URL + path.Join("/users/42", test.Path)
   539  		req, err := http.NewRequest(test.Method, u, nil)
   540  		r.NoError(err)
   541  		res, err := c.Do(req)
   542  		r.NoError(err)
   543  		b, err := ioutil.ReadAll(res.Body)
   544  		r.NoError(err)
   545  		r.Equal(test.Result, string(b))
   546  	}
   547  
   548  }
   549  
   550  func Test_buildRouteName(t *testing.T) {
   551  	r := require.New(t)
   552  	cases := map[string]string{
   553  		"/":                                          "root",
   554  		"/users":                                     "users",
   555  		"/users/new":                                 "newUsers",
   556  		"/users/{user_id}":                           "user",
   557  		"/users/{user_id}/children":                  "userChildren",
   558  		"/users/{user_id}/children/{child_id}":       "userChild",
   559  		"/users/{user_id}/children/new":              "newUserChildren",
   560  		"/users/{user_id}/children/{child_id}/build": "userChildBuild",
   561  		"/admin/planes":                              "adminPlanes",
   562  		"/admin/planes/{plane_id}":                   "adminPlane",
   563  		"/admin/planes/{plane_id}/edit":              "editAdminPlane",
   564  	}
   565  
   566  	a := New(Options{})
   567  
   568  	for input, result := range cases {
   569  		fResult := a.buildRouteName(input)
   570  		r.Equal(result, fResult, input)
   571  	}
   572  
   573  	a = New(Options{Prefix: "/test"})
   574  	cases = map[string]string{
   575  		"/test":       "test",
   576  		"/test/users": "testUsers",
   577  	}
   578  
   579  	for input, result := range cases {
   580  		fResult := a.buildRouteName(input)
   581  		r.Equal(result, fResult, input)
   582  	}
   583  }
   584  
   585  func Test_CatchAll_Route(t *testing.T) {
   586  	r := require.New(t)
   587  	rr := render.New(render.Options{})
   588  
   589  	a := New(Options{})
   590  	a.GET("/{name:.+}", func(c Context) error {
   591  		name := c.Param("name")
   592  		return c.Render(200, rr.String(name))
   593  	})
   594  
   595  	w := willie.New(a)
   596  	res := w.Request("/john").Get()
   597  
   598  	r.Contains(res.Body.String(), "john")
   599  }
   600  
   601  func Test_Router_Matches_Trailing_Slash(t *testing.T) {
   602  	r := require.New(t)
   603  
   604  	table := []string{
   605  		"/bar",
   606  		"/bar/",
   607  	}
   608  
   609  	ts := httptest.NewServer(testApp())
   610  	defer ts.Close()
   611  
   612  	for _, v := range table {
   613  		req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", ts.URL, v), nil)
   614  		r.NoError(err)
   615  		res, err := http.DefaultClient.Do(req)
   616  		r.NoError(err)
   617  		b, _ := ioutil.ReadAll(res.Body)
   618  		r.Equal("bar", string(b))
   619  	}
   620  }