package oltp
import (
"errors"
"testing"
)
func TestWithdrawnInviteFreesTheName(t *testing.T) {
db := testDB(t)
if err := db.AddRepo("shared", t.TempDir(), "", "public"); err != nil {
t.Fatal(err)
}
if _, err := db.InviteAccount("northrup", "[email protected]", false); err != nil {
t.Fatal(err)
}
if err := db.Grant("northrup", "shared", Write); err != nil {
t.Fatal(err)
}
if err := db.WithdrawInvite("northrup"); err != nil {
t.Fatal(err)
}
if _, ok := db.AccountByName("northrup"); ok {
t.Fatal("withdrawn invite left the account")
}
if db.Tombstoned("northrup") {
t.Fatal("withdrawn invite retired the name")
}
for _, q := range []string{
`SELECT count(*) FROM invite WHERE account = 'northrup'`,
`SELECT count(*) FROM repo_caps WHERE account = 'northrup'`,
} {
if n := countRows(t, db, q); n != 0 {
t.Fatalf("%s: %d rows left", q, n)
}
}
// The name is free: someone else can be invited under it, and they
// inherit none of the withdrawn account's grants.
if _, err := db.InviteAccount("northrup", "[email protected]", false); err != nil {
t.Fatalf("re-invite after withdraw: %v", err)
}
if caps, _ := db.CapsOf("northrup", "shared"); caps != "" {
t.Fatalf("successor inherited caps %q", caps)
}
}
func TestWithdrawRefusedForAUsedAccount(t *testing.T) {
db := testDB(t)
if err := db.AddAccount("bob", "pw-bob-12345", false); err != nil {
t.Fatal(err)
}
tok, err := db.InviteAccount("jan", "[email protected]", false)
if err != nil {
t.Fatal(err)
}
if _, err := db.RedeemInvite(tok, "pw-jan-12345"); err != nil {
t.Fatal(err)
}
if _, err := db.InviteAccount("lou", "[email protected]", false); err != nil {
t.Fatal(err)
}
if _, err := db.w.Exec(`UPDATE account SET last_login = 'x' WHERE name = 'lou'`); err != nil {
t.Fatal(err)
}
for _, name := range []string{"bob", "jan", "lou"} {
var ref Refusal
if err := db.WithdrawInvite(name); !errors.As(err, &ref) {
t.Fatalf("withdraw %s: want Refusal, got %v", name, err)
}
if _, ok := db.AccountByName(name); !ok {
t.Fatalf("refused withdraw removed %s", name)
}
}
if err := db.WithdrawInvite("nobody"); !errors.Is(err, ErrNoAccount) {
t.Fatalf("withdraw unknown: want ErrNoAccount, got %v", err)
}
}
func TestLastSeenFollowsUseNotJustSignIn(t *testing.T) {
db := testDB(t)
if err := db.AddAccount("bob", "pw-bob-12345", false); err != nil {
t.Fatal(err)
}
tok, _, ok := db.NewSession("bob", "pw-bob-12345")
if !ok {
t.Fatal("sign-in failed")
}
if _, err := db.w.Exec(`UPDATE session SET last_seen = '2000-01-01T00:00:00Z'`); err != nil {
t.Fatal(err)
}
if _, err := db.w.Exec(`UPDATE account SET last_seen = '2000-01-01T00:00:00Z', last_login = '2000-01-01T00:00:00Z'`); err != nil {
t.Fatal(err)
}
if _, ok := db.SessionAccount(tok); !ok {
t.Fatal("session did not resolve")
}
a, _ := db.AccountByName("bob")
if a.LastSeen == "2000-01-01T00:00:00Z" || a.LastSeen == "" {
t.Fatalf("a page view did not move last_seen: %q", a.LastSeen)
}
if a.LastLogin != "2000-01-01T00:00:00Z" {
t.Fatalf("a page view moved last_login: %q", a.LastLogin)
}
// Seen accounts are used accounts: their invite cannot be withdrawn.
if err := db.WithdrawInvite("bob"); err == nil {
t.Fatal("withdrew a used account")
}
}