package db import ( "errors" "testing" "time" ) func TestInvites(t *testing.T) { db := testDB(t) user := newTestUser(t, "poyo") if err := db.NewUser(user); err != nil { t.Fatalf("NewUser: %v", err) } invite, err := db.NewInvite(NewInviteOptions{ UserID: user.ID, Length: 8, Duration: time.Hour, }) if err != nil { t.Fatalf("NewInvite: %v", err) } if len(invite.Token) != 8 { t.Errorf("Token = %q, want 8 chars", invite.Token) } if !invite.ExpiresAt.After(time.Now()) { t.Error("ExpiresAt is not in the future") } if _, ok := db.ValidateInviteToken(invite.Token); !ok { t.Error("ValidateInviteToken(valid token) = false, want true") } if _, ok := db.ValidateInviteToken("bogus"); ok { t.Error("ValidateInviteToken(unknown token) = true, want false") } // an expired token validates as false and gets deleted expired, err := db.NewInvite(NewInviteOptions{ UserID: user.ID, Length: 8, Duration: -time.Minute, }) if err != nil { t.Fatalf("NewInvite(expired): %v", err) } if _, ok := db.ValidateInviteToken(expired.Token); ok { t.Error("ValidateInviteToken(expired) = true, want false") } if err := db.DeleteInviteToken(invite.Token); err != nil { t.Fatalf("DeleteInviteToken: %v", err) } if _, ok := db.ValidateInviteToken(invite.Token); ok { t.Error("ValidateInviteToken after delete = true, want false") } // expecting an error since the token is not valid invalidLen, err := db.NewInvite(NewInviteOptions{ UserID: user.ID, Length: 0, Duration: time.Hour, }) if err == nil { t.Fatalf("NewInvite(invalidLen): %v", err) } if _, ok := db.ValidateInviteToken(invalidLen.Token); ok { t.Error("ValidateInviteToken(invalidLen) = true, want false") } // should pass (anonymous invite) and its token must validate like any other anonymous, err := db.NewInvite(NewInviteOptions{ Length: 4, Duration: time.Hour, }) if err != nil { t.Fatalf("NewInvite(anonymous): %v", err) } if _, ok := db.ValidateInviteToken(anonymous.Token); !ok { t.Error("ValidateInviteToken(anonymous) = false, want true") } } func TestDeleteExpiredInviteTokens(t *testing.T) { db := testDB(t) user := newTestUser(t, "poyo") if err := db.NewUser(user); err != nil { t.Fatalf("NewUser: %v", err) } valid, err := db.NewInvite(NewInviteOptions{ UserID: user.ID, Length: 8, Duration: time.Hour, }) if err != nil { t.Fatal(err) } if _, err := db.NewInvite(NewInviteOptions{ UserID: user.ID, Length: 8, Duration: -time.Minute, }); err != nil { t.Fatal(err) } db.DeleteExpiredInviteTokens() if _, ok := db.ValidateInviteToken(valid.Token); !ok { t.Error("valid invite was Deleted") } } func TestNewUserWithInvite(t *testing.T) { db := testDB(t) inviter := newTestUser(t, "inviter") if err := db.NewUser(inviter); err != nil { t.Fatalf("NewUser: %v", err) } invite, err := db.NewInvite(NewInviteOptions{ UserID: inviter.ID, Length: 8, Duration: time.Hour, }) if err != nil { t.Fatal(err) } invitee := newTestUser(t, "invitee") if err := db.NewUserWithInvite(invitee, invite.Token); err != nil { t.Fatalf("NewUserWithInvite: %v", err) } // the token is consumed if _, ok := db.ValidateInviteToken(invite.Token); ok { t.Error("invite still valid after being used") } if _, err := db.UserHandle("invitee"); err != nil { t.Errorf("invitee was not created: %v", err) } // a bogus token creates no user other := newTestUser(t, "other") if err := db.NewUserWithInvite(other, "bogus"); !errors.Is(err, ErrInvalidInvite) { t.Errorf("NewUserWithInvite(bad token) = %v, want ErrInvalidInvite", err) } if _, err := db.UserHandle("other"); err == nil { t.Error("user was created despite an invalid invite token") } }