Skip to content
quarry Artifact [3c158350d9]
Login

Artifact [3c158350d9]

Artifact 3c158350d9fc9fa64d26cf6f266798205366583f9e8d61e1fa1ae81787b2c4d0:


package oltp

import (
	"sync"
	"testing"
)

// race runs fn on n goroutines released together, and returns how
// many returned nil — the count a check-then-write race inflates.
func race(n int, fn func(i int) error) (ok int, errs []error) {
	var start, done sync.WaitGroup
	start.Add(1)
	results := make([]error, n)
	for i := 0; i < n; i++ {
		done.Add(1)
		go func(i int) {
			defer done.Done()
			start.Wait()
			results[i] = fn(i)
		}(i)
	}
	start.Done()
	done.Wait()
	for _, err := range results {
		if err == nil {
			ok++
		} else {
			errs = append(errs, err)
		}
	}
	return ok, errs
}

func TestTwoRedemptionsOfOneInviteAtOnceLetExactlyOneThrough(t *testing.T) {
	db := testDB(t)
	token, err := db.InviteAccount("eve", "[email protected]", false)
	if err != nil {
		t.Fatal(err)
	}
	passwords := []string{"first-password-1", "second-password-2"}
	ok, errs := race(len(passwords), func(i int) error {
		_, err := db.RedeemInvite(token, passwords[i])
		return err
	})
	if ok != 1 {
		t.Fatalf("FAIL: %d of %d concurrent redemptions of one invite succeeded (errors %v)", ok, len(passwords), errs)
	}
	t.Logf("ok: one redemption won, the other was refused: %v", errs)
	signIns := 0
	for _, p := range passwords {
		if _, ok := db.Authenticate("eve", p); ok {
			signIns++
		}
	}
	if signIns != 1 {
		t.Fatalf("FAIL: %d passwords sign eve in after the race, want the winner's only", signIns)
	}
	t.Logf("ok: exactly the winning password signs in")
}

// rounds repeats a race whose window is a few statements wide: one
// round rarely lands both goroutines inside it, hundreds nearly always
// do.
const rounds = 300

func TestTwoAdminsDemotingEachOtherAtOnceLeaveTheRepositoryAnAdmin(t *testing.T) {
	db := testDB(t)
	for _, n := range []string{"alice", "bob"} {
		if err := db.AddAccount(n, "pw12345678", false); err != nil {
			t.Fatal(err)
		}
	}
	// Each demotes the other: alone, each save leaves one admin and
	// the guard passes it.
	pairs := [][2]string{{"alice", "bob"}, {"bob", "alice"}}
	for round := 0; round < rounds; round++ {
		for _, n := range []string{"alice", "bob"} {
			if err := db.Grant(n, "repo", RepoAdmin); err != nil {
				t.Fatal(err)
			}
		}
		ok, errs := race(len(pairs), func(i int) error {
			_, err := db.SetCapsGuarded(pairs[i][0], pairs[i][1], "repo", Write.Caps())
			return err
		})
		if ok != 1 {
			t.Fatalf("FAIL: round %d: %d of 2 crossing demotions succeeded (errors %v)", round, ok, errs)
		}
		if !IsRefusal(errs[0]) {
			t.Fatalf("FAIL: round %d: the losing demotion failed with %v, want the guard's refusal", round, errs[0])
		}
		if before, _, err := db.adminCount("repo", "", ""); err != nil || before != 1 {
			t.Fatalf("FAIL: round %d: the repository has %d admins after the race (%v), want 1", round, before, err)
		}
	}
	t.Logf("ok: in %d rounds one demotion went through, the other was refused, and one admin remained", rounds)
}

func TestTwoOwnersRemovingEachOtherAtOnceLeaveTheTeamAnOwner(t *testing.T) {
	for _, tc := range []struct {
		name  string
		apply func(db *DB, actor, account string) error
	}{
		{"removal", func(db *DB, actor, account string) error {
			_, err := db.RemoveTeamMemberGuarded(actor, "crew", account)
			return err
		}},
		{"demotion", func(db *DB, actor, account string) error {
			_, err := db.SetTeamMemberGuarded(actor, "crew", account, "", false, true)
			return err
		}},
	} {
		t.Run(tc.name, func(t *testing.T) {
			db := testDB(t)
			for _, n := range []string{"alice", "bob"} {
				if err := db.AddAccount(n, "pw12345678", false); err != nil {
					t.Fatal(err)
				}
			}
			if err := db.AddTeam("crew", "Crew", "", "alice"); err != nil {
				t.Fatal(err)
			}
			pairs := [][2]string{{"alice", "bob"}, {"bob", "alice"}}
			for round := 0; round < rounds; round++ {
				for _, n := range []string{"alice", "bob"} {
					if err := db.SetTeamMember("crew", n, "", true, true); err != nil {
						t.Fatal(err)
					}
				}
				ok, errs := race(len(pairs), func(i int) error {
					return tc.apply(db, pairs[i][0], pairs[i][1])
				})
				if ok != 1 {
					t.Fatalf("FAIL: round %d: %d of 2 crossing %ss succeeded (errors %v)", round, ok, tc.name, errs)
				}
				if !IsRefusal(errs[0]) {
					t.Fatalf("FAIL: round %d: the losing %s failed with %v, want the guard's refusal", round, tc.name, errs[0])
				}
				if n, err := db.TeamOwnerCount("crew"); err != nil || n != 1 {
					t.Fatalf("FAIL: round %d: the team has %d owners after the race (%v), want 1", round, n, err)
				}
			}
			t.Logf("ok: in %d rounds one %s went through, the other was refused, and one owner remained", rounds, tc.name)
		})
	}
}