示例#1
0
func TestAfterPasswordReset(t *testing.T) {
	t.Parallel()

	r := Remember{authboss.New()}

	id := "*****@*****.**"

	storer := mocks.NewMockStorer()
	r.Storer = storer
	session := mocks.NewMockClientStorer()
	cookies := mocks.NewMockClientStorer()
	storer.Tokens[id] = []string{"one", "two"}
	cookies.Values[authboss.CookieRemember] = "token"

	ctx := r.NewContext()
	ctx.User = authboss.Attributes{r.PrimaryID: id}
	ctx.SessionStorer = session
	ctx.CookieStorer = cookies

	if err := r.afterPassword(ctx); err != nil {
		t.Error(err)
	}

	if _, ok := cookies.Values[authboss.CookieRemember]; ok {
		t.Error("Expected the remember cookie to be deleted.")
	}

	if len(storer.Tokens) != 0 {
		t.Error("Should have wiped out all tokens.")
	}
}
示例#2
0
func TestAfterOAuth(t *testing.T) {
	t.Parallel()

	r := Remember{authboss.New()}
	storer := mocks.NewMockStorer()
	r.Storer = storer

	cookies := mocks.NewMockClientStorer()
	session := mocks.NewMockClientStorer(authboss.SessionOAuth2Params, `{"rm":"true"}`)

	ctx := r.NewContext()
	ctx.SessionStorer = session
	ctx.CookieStorer = cookies
	ctx.User = authboss.Attributes{
		authboss.StoreOAuth2UID:      "uid",
		authboss.StoreOAuth2Provider: "google",
	}

	if err := r.afterOAuth(ctx); err != nil {
		t.Error(err)
	}

	if _, ok := cookies.Values[authboss.CookieRemember]; !ok {
		t.Error("Expected a cookie to have been set.")
	}
}
示例#3
0
func TestAfterAuth(t *testing.T) {
	t.Parallel()

	r := Remember{authboss.New()}
	storer := mocks.NewMockStorer()
	r.Storer = storer

	cookies := mocks.NewMockClientStorer()
	session := mocks.NewMockClientStorer()

	req, err := http.NewRequest("POST", "http://localhost", bytes.NewBufferString("rm=true"))
	if err != nil {
		t.Error("Unexpected Error:", err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	ctx := r.NewContext()
	ctx.SessionStorer = session
	ctx.CookieStorer = cookies
	ctx.User = authboss.Attributes{r.PrimaryID: "*****@*****.**"}

	ctx.Values = map[string]string{authboss.CookieRemember: "true"}

	if err := r.afterAuth(ctx); err != nil {
		t.Error(err)
	}

	if _, ok := cookies.Values[authboss.CookieRemember]; !ok {
		t.Error("Expected a cookie to have been set.")
	}
}
示例#4
0
func TestConfirm_Confirm(t *testing.T) {
	t.Parallel()

	c := setup()
	ctx := c.NewContext()
	log := &bytes.Buffer{}
	c.LogWriter = log
	c.PrimaryID = authboss.StoreUsername
	c.Mailer = authboss.LogMailer(log)

	// Create a token
	token := []byte("hi")
	sum := md5.Sum(token)

	// Create the "database"
	storer := mocks.NewMockStorer()
	c.Storer = storer
	user := authboss.Attributes{
		authboss.StoreUsername: "******",
		StoreConfirmToken:      base64.StdEncoding.EncodeToString(sum[:]),
	}
	storer.Users["usern"] = user

	// Make a request with session and context support.
	r, _ := http.NewRequest("GET", "http://localhost?cnf="+base64.URLEncoding.EncodeToString(token), nil)
	w := httptest.NewRecorder()
	ctx = c.NewContext()
	ctx.CookieStorer = mocks.NewMockClientStorer()
	session := mocks.NewMockClientStorer()
	ctx.User = user
	ctx.SessionStorer = session

	c.confirmHandler(ctx, w, r)
	if w.Code != http.StatusFound {
		t.Error("Expected a redirect after success:", w.Code)
	}

	if log.Len() != 0 {
		t.Error("Expected a clean log on success:", log.String())
	}

	is, ok := ctx.User.Bool(StoreConfirmed)
	if !ok || !is {
		t.Error("The user should be confirmed.")
	}

	tok, ok := ctx.User.String(StoreConfirmToken)
	if ok && len(tok) != 0 {
		t.Error("Confirm token should have been wiped out.")
	}

	if key, ok := ctx.SessionStorer.Get(authboss.SessionKey); !ok || len(key) == 0 {
		t.Error("Should have logged the user in.")
	}
	if success, ok := ctx.SessionStorer.Get(authboss.FlashSuccessKey); !ok || len(success) == 0 {
		t.Error("Should have left a nice message.")
	}
}
示例#5
0
func TestNew(t *testing.T) {
	t.Parallel()

	r := &Remember{authboss.New()}
	storer := mocks.NewMockStorer()
	r.Storer = storer
	cookies := mocks.NewMockClientStorer()

	key := "tester"
	token, err := r.new(cookies, key)

	if err != nil {
		t.Error("Unexpected error:", err)
	}

	if len(token) == 0 {
		t.Error("Expected a token.")
	}

	if tok, ok := storer.Tokens[key]; !ok {
		t.Error("Expected it to store against the key:", key)
	} else if len(tok) != 1 || len(tok[0]) == 0 {
		t.Error("Expected a token to be saved.")
	}

	if token != cookies.Values[authboss.CookieRemember] {
		t.Error("Expected a cookie set with the token.")
	}
}
示例#6
0
func TestRegisterGet(t *testing.T) {
	reg := setup()

	w := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/register", nil)
	ctx := reg.NewContext()
	ctx.SessionStorer = mocks.NewMockClientStorer()

	if err := reg.registerHandler(ctx, w, r); err != nil {
		t.Error(err)
	}

	if w.Code != http.StatusOK {
		t.Error("It should have written a 200:", w.Code)
	}

	if w.Body.Len() == 0 {
		t.Error("It should have wrote a response.")
	}

	if str := w.Body.String(); !strings.Contains(str, "<form") {
		t.Error("It should have rendered a nice form:", str)
	} else if !strings.Contains(str, `name="`+reg.PrimaryID) {
		t.Error("Form should contain the primary ID:", str)
	}
}
示例#7
0
func TestOAuthFailure(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	oauth := OAuth2{ab}

	ab.OAuth2Providers = testProviders

	values := url.Values{}
	values.Set("error", "something")
	values.Set("error_reason", "auth_failure")
	values.Set("error_description", "Failed to auth.")

	ctx := ab.NewContext()
	session := mocks.NewMockClientStorer()
	session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)
	ctx.SessionStorer = session
	r, _ := http.NewRequest("GET", "/oauth2/google?"+values.Encode(), nil)

	err := oauth.oauthCallback(ctx, nil, r)
	if red, ok := err.(authboss.ErrAndRedirect); !ok {
		t.Error("Should be a redirect error")
	} else if len(red.FlashError) == 0 {
		t.Error("Should have a flash error.")
	} else if red.Err.Error() != "auth_failure" {
		t.Error("It should record the failure.")
	}
}
示例#8
0
func TestRedirect_Override(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	cookies := mocks.NewMockClientStorer()

	r, _ := http.NewRequest("GET", "http://localhost?redir=foo/bar", nil)
	w := httptest.NewRecorder()
	ctx, _ := ab.ContextFromRequest(r)
	ctx.SessionStorer = cookies

	Redirect(ctx, w, r, "/shouldNotGo", "success", "failure", true)

	if w.Code != http.StatusFound {
		t.Error("Expected a redirect.")
	}

	if w.Header().Get("Location") != "/foo/bar" {
		t.Error("Expected to be redirected to root.")
	}

	if val, _ := cookies.Get(authboss.FlashSuccessKey); val != "success" {
		t.Error("Flash success msg wrong:", val)
	}
	if val, _ := cookies.Get(authboss.FlashErrorKey); val != "failure" {
		t.Error("Flash failure msg wrong:", val)
	}
}
示例#9
0
func TestTemplates_Render(t *testing.T) {
	t.Parallel()

	cookies := mocks.NewMockClientStorer()
	ab := authboss.New()
	ab.LayoutDataMaker = func(_ http.ResponseWriter, _ *http.Request) authboss.HTMLData {
		return authboss.HTMLData{"fun": "is"}
	}
	ab.XSRFName = "do you think"
	ab.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
		return "that's air you're breathing now?"
	}

	// Set up flashes
	cookies.Put(authboss.FlashSuccessKey, "no")
	cookies.Put(authboss.FlashErrorKey, "spoon")

	r, _ := http.NewRequest("GET", "http://localhost", nil)
	w := httptest.NewRecorder()
	ctx, _ := ab.ContextFromRequest(r)
	ctx.SessionStorer = cookies

	tpls := Templates{
		"hello": testViewTemplate,
	}

	err := tpls.Render(ctx, w, r, "hello", authboss.HTMLData{"external": "there"})
	if err != nil {
		t.Error(err)
	}

	if w.Body.String() != "there is no spoon do you think that's air you're breathing now?" {
		t.Error("Body was wrong:", w.Body.String())
	}
}
示例#10
0
func testRequest(ab *authboss.Authboss, method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
	sessionStorer := mocks.NewMockClientStorer()
	ctx := ab.NewContext()
	r := mocks.MockRequest(method, postFormValues...)
	ctx.SessionStorer = sessionStorer

	return ctx, httptest.NewRecorder(), r, sessionStorer
}
示例#11
0
func TestAuth(t *testing.T) {
	t.Parallel()

	r := &Remember{authboss.New()}
	storer := mocks.NewMockStorer()
	r.Storer = storer

	cookies := mocks.NewMockClientStorer()
	session := mocks.NewMockClientStorer()
	ctx := r.NewContext()
	ctx.CookieStorer = cookies
	ctx.SessionStorer = session

	key := "tester"
	_, err := r.new(cookies, key)
	if err != nil {
		t.Error("Unexpected error:", err)
	}

	cookie, _ := cookies.Get(authboss.CookieRemember)

	interrupt, err := r.auth(ctx)
	if err != nil {
		t.Error("Unexpected error:", err)
	}

	if session.Values[authboss.SessionHalfAuthKey] != "true" {
		t.Error("The user should have been half-authed.")
	}

	if session.Values[authboss.SessionKey] != key {
		t.Error("The user should have been logged in.")
	}

	if chocolateChip, _ := cookies.Get(authboss.CookieRemember); chocolateChip == cookie {
		t.Error("Expected cookie to be different")
	}

	if authboss.InterruptNone != interrupt {
		t.Error("Keys should have matched:", interrupt)
	}
}
示例#12
0
func TestLogout(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	oauth := OAuth2{ab}
	ab.AuthLogoutOKPath = "/dashboard"

	r, _ := http.NewRequest("GET", "/oauth2/google?", nil)
	w := httptest.NewRecorder()

	ctx := ab.NewContext()
	session := mocks.NewMockClientStorer(authboss.SessionKey, "asdf", authboss.SessionLastAction, "1234")
	cookies := mocks.NewMockClientStorer(authboss.CookieRemember, "qwert")
	ctx.SessionStorer = session
	ctx.CookieStorer = cookies

	if err := oauth.logout(ctx, w, r); err != nil {
		t.Error(err)
	}

	if val, ok := session.Get(authboss.SessionKey); ok {
		t.Error("Unexpected session key:", val)
	}

	if val, ok := session.Get(authboss.SessionLastAction); ok {
		t.Error("Unexpected last action:", val)
	}

	if val, ok := cookies.Get(authboss.CookieRemember); ok {
		t.Error("Unexpected rm cookie:", val)
	}

	if http.StatusFound != w.Code {
		t.Errorf("Expected status code %d, got %d", http.StatusFound, w.Code)
	}

	location := w.Header().Get("Location")
	if location != ab.AuthLogoutOKPath {
		t.Error("Redirect wrong:", location)
	}
}
示例#13
0
func testRequest(ab *authboss.Authboss, method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
	r, err := http.NewRequest(method, "", nil)
	if err != nil {
		panic(err)
	}

	sessionStorer := mocks.NewMockClientStorer()
	ctx := mocks.MockRequestContext(ab, postFormValues...)
	ctx.SessionStorer = sessionStorer

	return ctx, httptest.NewRecorder(), r, sessionStorer
}
示例#14
0
func TestAfterOAuth(t *testing.T) {
	t.Parallel()

	r := Remember{authboss.New()}
	storer := mocks.NewMockStorer()
	r.Storer = storer

	cookies := mocks.NewMockClientStorer()
	session := mocks.NewMockClientStorer(authboss.SessionOAuth2Params, `{"rm":"true"}`)

	uri := fmt.Sprintf("%s?state=%s", "localhost/oauthed", "xsrf")
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		t.Error("Unexpected Error:", err)
	}

	ctx, err := r.ContextFromRequest(req)
	if err != nil {
		t.Error("Unexpected error:", err)
	}

	ctx.SessionStorer = session
	ctx.CookieStorer = cookies
	ctx.User = authboss.Attributes{
		authboss.StoreOAuth2UID:      "uid",
		authboss.StoreOAuth2Provider: "google",
	}

	if err := r.afterOAuth(ctx); err != nil {
		t.Error(err)
	}

	if _, ok := cookies.Values[authboss.CookieRemember]; !ok {
		t.Error("Expected a cookie to have been set.")
	}
}
示例#15
0
func TestRegisterPostSuccess(t *testing.T) {
	reg := setup()
	reg.Policies = nil

	w := httptest.NewRecorder()
	vals := url.Values{}

	email := "*****@*****.**"
	vals.Set(reg.PrimaryID, email)
	vals.Set(authboss.StorePassword, "pass")
	vals.Set(authboss.ConfirmPrefix+authboss.StorePassword, "pass")

	r, _ := http.NewRequest("POST", "/register", bytes.NewBufferString(vals.Encode()))
	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	ctx := reg.NewContext()
	ctx.SessionStorer = mocks.NewMockClientStorer()

	if err := reg.registerHandler(ctx, w, r); err != nil {
		t.Error(err)
	}

	if w.Code != http.StatusFound {
		t.Error("It should have written a redirect:", w.Code)
	}

	if loc := w.Header().Get("Location"); loc != reg.RegisterOKPath {
		t.Error("Redirected to the wrong location", loc)
	}

	user, err := reg.Storer.Get(email)
	if err == authboss.ErrUserNotFound {
		t.Error("The user have been saved.")
	}

	attrs := authboss.Unbind(user)
	if e, err := attrs.StringErr(reg.PrimaryID); err != nil {
		t.Error(err)
	} else if e != email {
		t.Errorf("Email was not set properly, want: %s, got: %s", email, e)
	}

	if p, err := attrs.StringErr(authboss.StorePassword); err != nil {
		t.Error(err)
	} else if p == "pass" {
		t.Error("Password was not hashed.")
	}
}
示例#16
0
func TestAuth_loginHandlerFunc_POST(t *testing.T) {
	t.Parallel()

	a, storer := testSetup()
	storer.Users["john"] = authboss.Attributes{"password": "******"}

	ctx, w, r, _ := testRequest(a.Authboss, "POST", "username", "john", "password", "1234")
	cb := mocks.NewMockAfterCallback()

	a.Callbacks = authboss.NewCallbacks()
	a.Callbacks.After(authboss.EventAuth, cb.Fn)
	a.AuthLoginOKPath = "/dashboard"

	sessions := mocks.NewMockClientStorer()
	ctx.SessionStorer = sessions

	if err := a.loginHandlerFunc(ctx, w, r); err != nil {
		t.Error("Unexpected error:", err)
	}

	if _, ok := ctx.Values[authboss.CookieRemember]; !ok {
		t.Error("Authboss cookie remember should be set for the callback")
	}
	if !cb.HasBeenCalled {
		t.Error("Expected after callback to have been called")
	}

	if w.Code != http.StatusFound {
		t.Error("Unexpected status:", w.Code)
	}

	loc := w.Header().Get("Location")
	if loc != a.AuthLoginOKPath {
		t.Error("Unexpeced location:", loc)
	}

	val, ok := sessions.Values[authboss.SessionKey]
	if !ok {
		t.Error("Expected session to be set")
	} else if val != "john" {
		t.Error("Expected session value to be authed username")
	}
}
示例#17
0
func TestOAuth2Init(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	oauth := OAuth2{ab}
	session := mocks.NewMockClientStorer()

	ab.OAuth2Providers = testProviders

	r, _ := http.NewRequest("GET", "/oauth2/google?redir=/my/redirect%23lol&rm=true", nil)
	w := httptest.NewRecorder()
	ctx := ab.NewContext()
	ctx.SessionStorer = session

	oauth.oauthInit(ctx, w, r)

	if w.Code != http.StatusFound {
		t.Error("Code was wrong:", w.Code)
	}

	loc := w.Header().Get("Location")
	parsed, err := url.Parse(loc)
	if err != nil {
		t.Error(err)
	}
	if !strings.Contains(loc, google.Endpoint.AuthURL) {
		t.Error("Redirected to wrong url:", loc)
	}

	query := parsed.Query()
	if query["include_requested_scopes"][0] != "true" {
		t.Error("Missing extra parameters:", loc)
	}
	state := query[authboss.FormValueOAuth2State][0]
	if len(state) == 0 {
		t.Error("It should have had some state:", loc)
	}

	if params := session.Values[authboss.SessionOAuth2Params]; params != `{"redir":"/my/redirect#lol","rm":"true"}` {
		t.Error("The params were wrong:", params)
	}
}
示例#18
0
func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
	t.Parallel()

	a, _ := testSetup()

	a.AuthLogoutOKPath = "/dashboard"

	ctx, w, r, sessionStorer := testRequest(a.Authboss, "GET")
	sessionStorer.Put(authboss.SessionKey, "asdf")
	sessionStorer.Put(authboss.SessionLastAction, "1234")

	cookieStorer := mocks.NewMockClientStorer(authboss.CookieRemember, "qwert")
	ctx.CookieStorer = cookieStorer

	if err := a.logoutHandlerFunc(ctx, w, r); err != nil {
		t.Error("Unexpected error:", err)
	}

	if val, ok := sessionStorer.Get(authboss.SessionKey); ok {
		t.Error("Unexpected session key:", val)
	}

	if val, ok := sessionStorer.Get(authboss.SessionLastAction); ok {
		t.Error("Unexpected last action:", val)
	}

	if val, ok := cookieStorer.Get(authboss.CookieRemember); ok {
		t.Error("Unexpected rm cookie:", val)
	}

	if http.StatusFound != w.Code {
		t.Errorf("Expected status code %d, got %d", http.StatusFound, w.Code)
	}

	location := w.Header().Get("Location")
	if location != "/dashboard" {
		t.Errorf("Expected lcoation %s, got %s", "/dashboard", location)
	}
}
示例#19
0
func TestRegisterPostValidationErrs(t *testing.T) {
	reg := setup()

	w := httptest.NewRecorder()
	vals := url.Values{}

	email := "*****@*****.**"
	vals.Set(reg.PrimaryID, email)
	vals.Set(authboss.StorePassword, "pass")
	vals.Set(authboss.ConfirmPrefix+authboss.StorePassword, "pass2")

	r, _ := http.NewRequest("POST", "/register", bytes.NewBufferString(vals.Encode()))
	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	ctx := reg.NewContext()
	ctx.SessionStorer = mocks.NewMockClientStorer()

	if err := reg.registerHandler(ctx, w, r); err != nil {
		t.Error(err)
	}

	if w.Code != http.StatusOK {
		t.Error("It should have written a 200:", w.Code)
	}

	if w.Body.Len() == 0 {
		t.Error("It should have wrote a response.")
	}

	if str := w.Body.String(); !strings.Contains(str, "Does not match password") {
		t.Error("Confirm password should have an error:", str)
	}

	if _, err := reg.Storer.Get(email); err != authboss.ErrUserNotFound {
		t.Error("The user should not have been saved.")
	}
}
示例#20
0
func TestOAuthXSRFFailure(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	oauth := OAuth2{ab}

	session := mocks.NewMockClientStorer()
	session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)

	ab.OAuth2Providers = testProviders

	values := url.Values{}
	values.Set(authboss.FormValueOAuth2State, "notstate")
	values.Set("code", "code")

	ctx := ab.NewContext()
	ctx.SessionStorer = session
	r, _ := http.NewRequest("GET", "/oauth2/google?"+values.Encode(), nil)

	err := oauth.oauthCallback(ctx, nil, r)
	if err != errOAuthStateValidation {
		t.Error("Should have gotten an error about state validation:", err)
	}
}
示例#21
0
func TestOAuthSuccess(t *testing.T) {
	t.Parallel()

	ab := authboss.New()
	oauth := OAuth2{ab}

	expiry := time.Now().UTC().Add(3600 * time.Second)
	fakeToken := &oauth2.Token{
		AccessToken:  "token",
		TokenType:    "Bearer",
		RefreshToken: "refresh",
		Expiry:       expiry,
	}

	fakeCallback := func(_ oauth2.Config, _ *oauth2.Token) (authboss.Attributes, error) {
		return authboss.Attributes{
			authboss.StoreOAuth2UID: "uid",
			authboss.StoreEmail:     "email",
		}, nil
	}

	saveExchange := exchanger
	defer func() {
		exchanger = saveExchange
	}()
	exchanger = func(_ *oauth2.Config, _ context.Context, _ string) (*oauth2.Token, error) {
		return fakeToken, nil
	}

	ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
		"fake": authboss.OAuth2Provider{
			OAuth2Config: &oauth2.Config{
				ClientID:     `jazz`,
				ClientSecret: `hands`,
				Scopes:       []string{`profile`, `email`},
				Endpoint: oauth2.Endpoint{
					AuthURL:  "fakeauth",
					TokenURL: "faketoken",
				},
			},
			Callback:         fakeCallback,
			AdditionalParams: url.Values{"include_requested_scopes": []string{"true"}},
		},
	}

	values := make(url.Values)
	values.Set("code", "code")
	values.Set("state", "state")

	url := fmt.Sprintf("/oauth2/fake?%s", values.Encode())
	r, _ := http.NewRequest("GET", url, nil)
	w := httptest.NewRecorder()
	ctx := ab.NewContext()
	session := mocks.NewMockClientStorer()
	session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)
	session.Put(authboss.SessionOAuth2Params, `{"redir":"/myurl?myparam=5","rm":"true"}`)

	storer := mocks.NewMockStorer()
	ctx.SessionStorer = session
	ab.OAuth2Storer = storer
	ab.AuthLoginOKPath = "/fakeloginok"

	if err := oauth.oauthCallback(ctx, w, r); err != nil {
		t.Error(err)
	}

	key := "uidfake"
	user, ok := storer.Users[key]
	if !ok {
		t.Error("Couldn't find user.")
	}

	if val, _ := user.String(authboss.StoreEmail); val != "email" {
		t.Error("Email was wrong:", val)
	}
	if val, _ := user.String(authboss.StoreOAuth2Token); val != "token" {
		t.Error("Token was wrong:", val)
	}
	if val, _ := user.String(authboss.StoreOAuth2Refresh); val != "refresh" {
		t.Error("Refresh was wrong:", val)
	}
	if val, _ := user.DateTime(authboss.StoreOAuth2Expiry); !val.Equal(expiry) {
		t.Error("Expiry was wrong:", val)
	}

	if val, _ := session.Get(authboss.SessionKey); val != "uid;fake" {
		t.Error("User was not logged in:", val)
	}
	if _, ok := session.Get(authboss.SessionOAuth2State); ok {
		t.Error("Expected state to be deleted.")
	}

	if w.Code != http.StatusFound {
		t.Error("It should redirect")
	} else if loc := w.Header().Get("Location"); loc != "/myurl?myparam=5" {
		t.Error("Redirect is wrong:", loc)
	}
}