github.com/naoina/kocha@v0.7.1-0.20171129072645-78c7a531f799/middleware_test.go (about) 1 package kocha_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "mime/multipart" 8 "net/http" 9 "net/http/httptest" 10 "reflect" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/naoina/kocha" 16 "github.com/naoina/kocha/log" 17 "github.com/naoina/kocha/util" 18 ) 19 20 func TestPanicRecoverMiddleware(t *testing.T) { 21 test := func(ident string, w *httptest.ResponseRecorder) { 22 var actual interface{} = w.Code 23 var expect interface{} = http.StatusInternalServerError 24 if !reflect.DeepEqual(actual, expect) { 25 t.Errorf(`PanicRecoverMiddleware: %s; status => %#v; want %#v`, ident, actual, expect) 26 } 27 28 actual = w.Body.String() 29 expect = "This is layout\n500 error\n\n" 30 if !reflect.DeepEqual(actual, expect) { 31 t.Errorf(`PanicRecoverMiddleware: %s => %#v; want %#v`, ident, actual, expect) 32 } 33 34 actual = w.Header().Get("Content-Type") 35 expect = "text/html" 36 if !reflect.DeepEqual(actual, expect) { 37 t.Errorf(`PanicRecoverMiddleware: %s; Context-Type => %#v; want %#v`, ident, actual, expect) 38 } 39 } 40 41 func() { 42 req, err := http.NewRequest("GET", "/error", nil) 43 if err != nil { 44 t.Fatal(err) 45 } 46 app := kocha.NewTestApp() 47 app.Config.Middlewares = []kocha.Middleware{ 48 &kocha.PanicRecoverMiddleware{}, 49 &kocha.DispatchMiddleware{}, 50 } 51 var buf bytes.Buffer 52 app.Logger = log.New(&buf, &log.LTSVFormatter{}, app.Config.Logger.Level) 53 w := httptest.NewRecorder() 54 app.ServeHTTP(w, req) 55 test(`GET "/error"`, w) 56 57 actual := strings.SplitN(buf.String(), "\n", 2)[0] 58 expect := "\tmessage:panic test" 59 if !strings.Contains(actual, expect) { 60 t.Errorf(`PanicRecoverMiddleware: GET "/error"; log => %#v; want contains => %#v`, actual, expect) 61 } 62 }() 63 64 func() { 65 req, err := http.NewRequest("GET", "/", nil) 66 if err != nil { 67 t.Fatal(err) 68 } 69 app := kocha.NewTestApp() 70 app.Config.Middlewares = []kocha.Middleware{ 71 &kocha.PanicRecoverMiddleware{}, 72 &TestPanicInBeforeMiddleware{}, 73 &kocha.DispatchMiddleware{}, 74 } 75 var buf bytes.Buffer 76 app.Logger = log.New(&buf, &log.LTSVFormatter{}, app.Config.Logger.Level) 77 w := httptest.NewRecorder() 78 app.ServeHTTP(w, req) 79 test(`GET "/"`, w) 80 81 actual := strings.SplitN(buf.String(), "\n", 2)[0] 82 expect := "\tmessage:before" 83 if !strings.Contains(actual, expect) { 84 t.Errorf(`PanicRecoverMiddleware: GET "/error"; log => %#v; want contains => %#v`, actual, expect) 85 } 86 }() 87 88 func() { 89 req, err := http.NewRequest("GET", "/", nil) 90 if err != nil { 91 t.Fatal(err) 92 } 93 app := kocha.NewTestApp() 94 app.Config.Middlewares = []kocha.Middleware{ 95 &kocha.PanicRecoverMiddleware{}, 96 &TestPanicInAfterMiddleware{}, 97 &kocha.DispatchMiddleware{}, 98 } 99 var buf bytes.Buffer 100 app.Logger = log.New(&buf, &log.LTSVFormatter{}, app.Config.Logger.Level) 101 w := httptest.NewRecorder() 102 app.ServeHTTP(w, req) 103 test(`GET "/"`, w) 104 105 actual := strings.SplitN(buf.String(), "\n", 2)[0] 106 expect := "\tmessage:after" 107 if !strings.Contains(actual, expect) { 108 t.Errorf(`PanicRecoverMiddleware: GET "/error"; log => %#v; want contains => %#v`, actual, expect) 109 } 110 }() 111 112 func() { 113 defer func() { 114 actual := recover() 115 expect := "before" 116 if !reflect.DeepEqual(actual, expect) { 117 t.Errorf(`PanicRecoverMiddleware after panic middleware: GET "/" => %#v; want %#v`, actual, expect) 118 } 119 }() 120 req, err := http.NewRequest("GET", "/", nil) 121 if err != nil { 122 t.Fatal(err) 123 } 124 app := kocha.NewTestApp() 125 app.Config.Middlewares = []kocha.Middleware{ 126 &TestPanicInBeforeMiddleware{}, 127 &kocha.PanicRecoverMiddleware{}, 128 &kocha.DispatchMiddleware{}, 129 } 130 w := httptest.NewRecorder() 131 app.ServeHTTP(w, req) 132 }() 133 134 func() { 135 defer func() { 136 actual := recover() 137 expect := "after" 138 if !reflect.DeepEqual(actual, expect) { 139 t.Errorf(`PanicRecoverMiddleware after panic middleware: GET "/" => %#v; want %#v`, actual, expect) 140 } 141 }() 142 req, err := http.NewRequest("GET", "/", nil) 143 if err != nil { 144 t.Fatal(err) 145 } 146 app := kocha.NewTestApp() 147 app.Config.Middlewares = []kocha.Middleware{ 148 &TestPanicInAfterMiddleware{}, 149 &kocha.PanicRecoverMiddleware{}, 150 &kocha.DispatchMiddleware{}, 151 } 152 w := httptest.NewRecorder() 153 app.ServeHTTP(w, req) 154 }() 155 } 156 157 func TestFormMiddleware(t *testing.T) { 158 doTest := func(body io.Reader, contentType string) { 159 app := kocha.NewTestApp() 160 r, err := http.NewRequest("POST", "/?q=test&t=jp", body) 161 if err != nil { 162 t.Fatal(err) 163 } 164 r.Header.Set("Content-Type", contentType) 165 req, res := &kocha.Request{Request: r}, &kocha.Response{ResponseWriter: httptest.NewRecorder()} 166 c := &kocha.Context{ 167 Request: req, 168 Response: res, 169 } 170 m := &kocha.FormMiddleware{} 171 if err := m.Process(app, c, func() error { 172 var actual interface{} = c.Params.Encode() 173 var expect interface{} = "f=bob&n=alice&q=test&t=jp" 174 if !reflect.DeepEqual(actual, expect) { 175 t.Errorf(`FormMiddleware.Process(app, c, func); c.Params => %#v; want %#v`, actual, expect) 176 } 177 return nil 178 }); err != nil { 179 t.Fatal(err) 180 } 181 } 182 183 // test with x-www-form-urlencoded 184 func() { 185 doTest(bytes.NewBufferString("n=alice&f=bob"), "application/x-www-form-urlencoded") 186 }() 187 188 // test with multipart/form-data 189 func() { 190 var body bytes.Buffer 191 w := multipart.NewWriter(&body) 192 for _, v := range [][2]string{ 193 {"n", "alice"}, 194 {"f", "bob"}, 195 } { 196 if err := w.WriteField(v[0], v[1]); err != nil { 197 t.Fatal(err) 198 } 199 } 200 w.Close() 201 doTest(&body, w.FormDataContentType()) 202 }() 203 } 204 205 func newTestSessionMiddleware(store kocha.SessionStore) *kocha.SessionMiddleware { 206 return &kocha.SessionMiddleware{ 207 Name: "test_session", 208 Store: store, 209 ExpiresKey: "test.expires.key", 210 } 211 } 212 213 func TestSessionMiddleware_Before(t *testing.T) { 214 newRequestResponse := func(cookie *http.Cookie) (*kocha.Request, *kocha.Response) { 215 r, err := http.NewRequest("GET", "/", nil) 216 if err != nil { 217 t.Fatal(err) 218 } 219 req := &kocha.Request{Request: r} 220 if cookie != nil { 221 req.AddCookie(cookie) 222 } 223 res := &kocha.Response{ResponseWriter: httptest.NewRecorder()} 224 return req, res 225 } 226 227 origNow := util.Now 228 util.Now = func() time.Time { return time.Unix(1383820443, 0) } 229 defer func() { 230 util.Now = origNow 231 }() 232 233 // test new session 234 func() { 235 app := kocha.NewTestApp() 236 req, res := newRequestResponse(nil) 237 c := &kocha.Context{Request: req, Response: res} 238 m := &kocha.SessionMiddleware{Store: &NullSessionStore{}} 239 err := m.Process(app, c, func() error { 240 actual := c.Session 241 expected := make(kocha.Session) 242 if !reflect.DeepEqual(actual, expected) { 243 t.Errorf("Expect %v, but %v", expected, actual) 244 } 245 return fmt.Errorf("expected error") 246 }) 247 var actual interface{} = err 248 var expect interface{} = fmt.Errorf("expected error") 249 if !reflect.DeepEqual(actual, expect) { 250 t.Errorf(`kocha.SessionMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 251 } 252 actual = c.Session 253 expect = make(kocha.Session) 254 if !reflect.DeepEqual(actual, expect) { 255 t.Errorf("Expect %v, but %v", expect, actual) 256 } 257 }() 258 259 // test expires not found 260 func() { 261 app := kocha.NewTestApp() 262 store := kocha.NewTestSessionCookieStore() 263 sess := make(kocha.Session) 264 value, err := store.Save(sess) 265 if err != nil { 266 t.Fatal(err) 267 } 268 m := newTestSessionMiddleware(store) 269 cookie := &http.Cookie{ 270 Name: m.Name, 271 Value: value, 272 } 273 req, res := newRequestResponse(cookie) 274 c := &kocha.Context{Request: req, Response: res} 275 err = m.Process(app, c, func() error { 276 actual := c.Session 277 expected := make(kocha.Session) 278 if !reflect.DeepEqual(actual, expected) { 279 t.Errorf("Expect %v, but %v", expected, actual) 280 } 281 return fmt.Errorf("expected error") 282 }) 283 var actual interface{} = err 284 var expect interface{} = fmt.Errorf("expected error") 285 if !reflect.DeepEqual(actual, expect) { 286 t.Errorf(`kocha.SessionMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 287 } 288 actual = c.Session 289 expect = make(kocha.Session) 290 if !reflect.DeepEqual(actual, expect) { 291 t.Errorf("Expect %v, but %v", expect, actual) 292 } 293 }() 294 295 // test expires invalid time format 296 func() { 297 app := kocha.NewTestApp() 298 store := kocha.NewTestSessionCookieStore() 299 m := newTestSessionMiddleware(store) 300 sess := make(kocha.Session) 301 sess[m.ExpiresKey] = "invalid format" 302 value, err := store.Save(sess) 303 if err != nil { 304 t.Fatal(err) 305 } 306 cookie := &http.Cookie{ 307 Name: m.Name, 308 Value: value, 309 } 310 req, res := newRequestResponse(cookie) 311 c := &kocha.Context{Request: req, Response: res} 312 err = m.Process(app, c, func() error { 313 actual := c.Session 314 expect := make(kocha.Session) 315 if !reflect.DeepEqual(actual, expect) { 316 t.Errorf("Expect %v, but %v", expect, actual) 317 } 318 return fmt.Errorf("expected error") 319 }) 320 var actual interface{} = err 321 var expect interface{} = fmt.Errorf("expected error") 322 if !reflect.DeepEqual(actual, expect) { 323 t.Errorf(`kocha.SessionMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 324 } 325 actual = c.Session 326 expect = make(kocha.Session) 327 if !reflect.DeepEqual(actual, expect) { 328 t.Errorf("Expect %v, but %v", expect, actual) 329 } 330 }() 331 332 // test expired 333 func() { 334 app := kocha.NewTestApp() 335 store := kocha.NewTestSessionCookieStore() 336 m := newTestSessionMiddleware(store) 337 sess := make(kocha.Session) 338 sess[m.ExpiresKey] = "1383820442" 339 value, err := store.Save(sess) 340 if err != nil { 341 t.Fatal(err) 342 } 343 cookie := &http.Cookie{ 344 Name: m.Name, 345 Value: value, 346 } 347 req, res := newRequestResponse(cookie) 348 c := &kocha.Context{Request: req, Response: res} 349 err = m.Process(app, c, func() error { 350 actual := c.Session 351 expected := make(kocha.Session) 352 if !reflect.DeepEqual(actual, expected) { 353 t.Errorf("Expect %v, but %v", expected, actual) 354 } 355 return fmt.Errorf("expected error") 356 }) 357 var actual interface{} = err 358 var expect interface{} = fmt.Errorf("expected error") 359 if !reflect.DeepEqual(actual, expect) { 360 t.Errorf(`kocha.SessionMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 361 } 362 actual = c.Session 363 expect = make(kocha.Session) 364 if !reflect.DeepEqual(actual, expect) { 365 t.Errorf("Expect %v, but %v", expect, actual) 366 } 367 }() 368 369 func() { 370 app := kocha.NewTestApp() 371 store := kocha.NewTestSessionCookieStore() 372 m := newTestSessionMiddleware(store) 373 sess := make(kocha.Session) 374 sess[m.ExpiresKey] = "1383820443" 375 sess["brown fox"] = "lazy dog" 376 value, err := store.Save(sess) 377 if err != nil { 378 t.Fatal(err) 379 } 380 cookie := &http.Cookie{ 381 Name: m.Name, 382 Value: value, 383 } 384 req, res := newRequestResponse(cookie) 385 c := &kocha.Context{Request: req, Response: res} 386 err = m.Process(app, c, func() error { 387 return fmt.Errorf("expected error") 388 }) 389 var actual interface{} = err 390 var expect interface{} = fmt.Errorf("expected error") 391 if !reflect.DeepEqual(actual, expect) { 392 t.Errorf(`kocha.SessionMiddlware.Process(app, c, func) => %#v; want %#v`, actual, expect) 393 } 394 actual = c.Session 395 expect = kocha.Session{ 396 m.ExpiresKey: "1383820443", 397 "brown fox": "lazy dog", 398 } 399 if !reflect.DeepEqual(actual, expect) { 400 t.Errorf("Expect %v, but %v", expect, actual) 401 } 402 }() 403 } 404 405 func TestSessionMiddleware_After(t *testing.T) { 406 app := kocha.NewTestApp() 407 origNow := util.Now 408 util.Now = func() time.Time { return time.Unix(1383820443, 0) } 409 defer func() { 410 util.Now = origNow 411 }() 412 r, err := http.NewRequest("GET", "/", nil) 413 if err != nil { 414 t.Fatal(err) 415 } 416 w := httptest.NewRecorder() 417 req, res := &kocha.Request{Request: r}, &kocha.Response{ResponseWriter: w} 418 c := &kocha.Context{Request: req, Response: res} 419 c.Session = make(kocha.Session) 420 m := &kocha.SessionMiddleware{Store: &NullSessionStore{}} 421 m.SessionExpires = time.Duration(1) * time.Second 422 m.CookieExpires = time.Duration(2) * time.Second 423 if err := m.Process(app, c, func() error { 424 return nil 425 }); err != nil { 426 t.Error(err) 427 } 428 var ( 429 actual interface{} = c.Session 430 expected interface{} = kocha.Session{ 431 m.ExpiresKey: "1383820444", // + time.Duration(1) * time.Second 432 } 433 ) 434 if !reflect.DeepEqual(actual, expected) { 435 t.Errorf("Expect %v, but %v", expected, actual) 436 } 437 438 c.Session[m.ExpiresKey] = "1383820444" 439 value, err := m.Store.Save(c.Session) 440 if err != nil { 441 t.Fatal(err) 442 } 443 c1 := res.Cookies()[0] 444 c2 := &http.Cookie{ 445 Name: m.Name, 446 Value: value, 447 Path: "/", 448 Expires: util.Now().UTC().Add(m.CookieExpires), 449 MaxAge: 2, 450 Secure: false, 451 HttpOnly: m.HttpOnly, 452 } 453 actual = c1.Name 454 expected = c2.Name 455 if !reflect.DeepEqual(actual, expected) { 456 t.Errorf("Expect %v, but %v", expected, actual) 457 } 458 actual, err = m.Store.Load(c1.Value) 459 if err != nil { 460 t.Error(err) 461 } 462 expected, err = m.Store.Load(c2.Value) 463 if err != nil { 464 t.Error(err) 465 } 466 if !reflect.DeepEqual(actual, expected) { 467 t.Errorf("Expect %v, but %v", expected, actual) 468 } 469 actual = c1.Path 470 expected = c2.Path 471 if !reflect.DeepEqual(actual, expected) { 472 t.Errorf("Expect %v, but %v", expected, actual) 473 } 474 actual = c1.Expires 475 expected = c2.Expires 476 if !reflect.DeepEqual(actual, expected) { 477 t.Errorf("Expect %v, but %v", expected, actual) 478 } 479 actual = c1.MaxAge 480 expected = c2.MaxAge 481 if !reflect.DeepEqual(actual, expected) { 482 t.Errorf("Expect %v, but %v", expected, actual) 483 } 484 actual = c1.Secure 485 expected = c2.Secure 486 if !reflect.DeepEqual(actual, expected) { 487 t.Errorf("Expect %v, but %v", expected, actual) 488 } 489 actual = c1.HttpOnly 490 expected = c2.HttpOnly 491 if !reflect.DeepEqual(actual, expected) { 492 t.Errorf("Expect %v, but %v", expected, actual) 493 } 494 } 495 496 type ValidateTestSessionStore struct{ validated bool } 497 498 func (s *ValidateTestSessionStore) Save(sess kocha.Session) (string, error) { return "", nil } 499 func (s *ValidateTestSessionStore) Load(key string) (kocha.Session, error) { return nil, nil } 500 func (s *ValidateTestSessionStore) Validate() error { 501 s.validated = true 502 return fmt.Errorf("session store validate error") 503 } 504 505 type NullSessionStore struct{} 506 507 func (s *NullSessionStore) Save(sess kocha.Session) (string, error) { 508 return "", nil 509 } 510 511 func (s *NullSessionStore) Load(key string) (kocha.Session, error) { 512 return nil, nil 513 } 514 515 func (s *NullSessionStore) Validate() error { 516 return nil 517 } 518 519 func TestSessionMiddleware_Validate(t *testing.T) { 520 for _, v := range []struct { 521 m *kocha.SessionMiddleware 522 expect interface{} 523 }{ 524 {(*kocha.SessionMiddleware)(nil), fmt.Errorf("kocha: session: middleware is nil")}, 525 {&kocha.SessionMiddleware{}, fmt.Errorf("kocha: session: because Store is nil, session cannot be used")}, 526 {&kocha.SessionMiddleware{ 527 Store: &ValidateTestSessionStore{}, 528 }, fmt.Errorf("kocha: session: Name must be specified")}, 529 {&kocha.SessionMiddleware{Name: "test_session"}, fmt.Errorf("kocha: session: because Store is nil, session cannot be used")}, 530 {&kocha.SessionMiddleware{ 531 Name: "test_session", 532 Store: &ValidateTestSessionStore{}, 533 }, fmt.Errorf("session store validate error")}, 534 {&kocha.SessionMiddleware{ 535 Name: "test_session", 536 Store: &NullSessionStore{}, 537 }, nil}, 538 } { 539 actual := v.m.Validate() 540 expect := v.expect 541 if !reflect.DeepEqual(actual, expect) { 542 t.Errorf(`kocha.SessionMiddleware.Validate() with %#v => %#v; want %#v`, v.m, actual, expect) 543 } 544 } 545 546 for _, v := range []struct { 547 m *kocha.SessionMiddleware 548 expect string 549 }{ 550 {&kocha.SessionMiddleware{}, "_kocha._sess._expires"}, 551 {&kocha.SessionMiddleware{ExpiresKey: "test.expires.key"}, "test.expires.key"}, 552 } { 553 v.m.Name = "test_session" 554 v.m.Store = &NullSessionStore{} 555 if err := v.m.Validate(); err != nil { 556 t.Error(err) 557 } 558 actual := v.m.ExpiresKey 559 expect := v.expect 560 if !reflect.DeepEqual(actual, expect) { 561 t.Errorf(`kocha.SessionMiddleware.Validate(); ExpiresKey => %#v; want %#v`, actual, expect) 562 } 563 } 564 } 565 566 func TestFlashMiddleware_Before_withNilSession(t *testing.T) { 567 app := kocha.NewTestApp() 568 m := &kocha.FlashMiddleware{} 569 c := &kocha.Context{Session: nil} 570 err := m.Process(app, c, func() error { 571 actual := c.Flash 572 expect := kocha.Flash(nil) 573 if !reflect.DeepEqual(actual, expect) { 574 t.Errorf(`FlashMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 575 } 576 return fmt.Errorf("expected error") 577 }) 578 var actual interface{} = err 579 var expect interface{} = fmt.Errorf("expected error") 580 if !reflect.DeepEqual(actual, expect) { 581 t.Errorf(`kocha.FlashMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 582 } 583 actual = c.Flash 584 expect = kocha.Flash(nil) 585 if !reflect.DeepEqual(actual, expect) { 586 t.Errorf(`FlashMiddleware.Process(app, c, func) => %#v; want %#v`, actual, expect) 587 } 588 } 589 590 func TestFlashMiddleware(t *testing.T) { 591 app := kocha.NewTestApp() 592 m := &kocha.FlashMiddleware{} 593 c := &kocha.Context{Session: make(kocha.Session)} 594 if err := m.Process(app, c, func() error { 595 actual := c.Flash.Len() 596 expect := 0 597 if !reflect.DeepEqual(actual, expect) { 598 t.Errorf(`FlashMiddleware.Process(app, c, func); c.Flash.Len() => %#v; want %#v`, actual, expect) 599 } 600 c.Flash.Set("test_param", "abc") 601 return nil 602 }); err != nil { 603 t.Error(err) 604 } 605 606 c.Flash = nil 607 if err := m.Process(app, c, func() error { 608 var actual interface{} = c.Flash.Len() 609 var expected interface{} = 1 610 if !reflect.DeepEqual(actual, expected) { 611 t.Errorf(`FlashMiddleware.Process(app, c, func) then Process(app, c, func); c.Flash.Len() => %#v; want %#v`, actual, expected) 612 } 613 actual = c.Flash.Get("test_param") 614 expected = "abc" 615 if !reflect.DeepEqual(actual, expected) { 616 t.Errorf(`FlashMiddleware.Process(app, c, func) then Process(app, c, func); c.Flash.Get("test_param") => %#v; want %#v`, actual, expected) 617 } 618 return nil 619 }); err != nil { 620 t.Error(err) 621 } 622 623 c.Flash = nil 624 if err := m.Process(app, c, func() error { 625 var actual interface{} = c.Flash.Len() 626 var expected interface{} = 0 627 if !reflect.DeepEqual(actual, expected) { 628 t.Errorf(`FlashMiddleware.Process(app, c, func) then Process(app, c, func); emulated redirect; c.Flash.Len() => %#v; want %#v`, actual, expected) 629 } 630 actual = c.Flash.Get("test_param") 631 expected = "" 632 if !reflect.DeepEqual(actual, expected) { 633 t.Errorf(`FlashMiddleware.Process(app, c, func) then Process(app, c, func); emulated redirect; c.Flash.Get("test_param") => %#v; want %#v`, actual, expected) 634 } 635 return nil 636 }); err != nil { 637 t.Error(err) 638 } 639 }