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