Beta servers: testers can use beta features in servers whose owner opted in
- beta.Configure takes the opted-in servers; testers are looked up in the beta server - beta commands registered per opted-in server and removed when it opts out - beta.ServerEnabled for behaviour that no person triggers - docs updated Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
e2fe30b524
commit
fcf4f3ccbd
12 files changed
+491
-122
No files matched your search
+146
-21
@@ -1,35 +1,54 @@
|
||||
package beta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
const (
|
||||
betaGuild = "1170934850157547600"
|
||||
testerRol = "555000000000000001"
|
||||
betaGuild = "1170934850157547600"
|
||||
otherGuild = "999000000000000001"
|
||||
testerRol = "555000000000000001"
|
||||
testerID = "777000000000000001"
|
||||
)
|
||||
|
||||
func member(roles ...string) *discordgo.Member { return &discordgo.Member{Roles: roles} }
|
||||
func member(roles ...string) *discordgo.Member {
|
||||
return &discordgo.Member{Roles: roles, User: &discordgo.User{ID: testerID}}
|
||||
}
|
||||
|
||||
func interaction(guildID string, m *discordgo.Member) *discordgo.InteractionCreate {
|
||||
return &discordgo.InteractionCreate{Interaction: &discordgo.Interaction{GuildID: guildID, Member: m}}
|
||||
}
|
||||
|
||||
func TestAllowed(t *testing.T) {
|
||||
// useLookup makes the beta server say who holds which roles, as Discord would.
|
||||
func useLookup(t *testing.T, rolesByUser map[string][]string, err error) *int {
|
||||
t.Helper()
|
||||
calls := 0
|
||||
SetRolesLookup(func(guildID, userID string) ([]string, error) {
|
||||
calls++
|
||||
if guildID != betaGuild {
|
||||
t.Errorf("the lookup must ask the beta server, asked %q", guildID)
|
||||
}
|
||||
return rolesByUser[userID], err
|
||||
})
|
||||
t.Cleanup(func() { lookup.Store(nil) })
|
||||
return &calls
|
||||
}
|
||||
|
||||
func TestAllowedInTheBetaServer(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
guild, role string // configuration
|
||||
inGuild string
|
||||
member *discordgo.Member
|
||||
want bool
|
||||
inBeta, hasRole bool
|
||||
name string
|
||||
guild, role string // configuration
|
||||
inGuild string
|
||||
member *discordgo.Member
|
||||
want bool
|
||||
on, hasRole bool
|
||||
}{
|
||||
{"tester in the beta server", betaGuild, testerRol, betaGuild, member("1", testerRol), true, true, true},
|
||||
{"member without the role", betaGuild, testerRol, betaGuild, member("1", "2"), false, true, false},
|
||||
{"member with no roles at all", betaGuild, testerRol, betaGuild, member(), false, true, false},
|
||||
{"the role in another server doesn't count", betaGuild, testerRol, "999000000000000001", member(testerRol), false, false, false},
|
||||
{"a DM has no member", betaGuild, testerRol, "", nil, false, false, false},
|
||||
{"a nil member in the beta server", betaGuild, testerRol, betaGuild, nil, false, true, false},
|
||||
{"no role configured: nobody", betaGuild, "", betaGuild, member(testerRol, ""), false, true, false},
|
||||
@@ -41,7 +60,7 @@ func TestAllowed(t *testing.T) {
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
Configure(tc.guild, tc.role)
|
||||
Configure(tc.guild, tc.role, nil)
|
||||
if got := Allowed(tc.inGuild, tc.member); got != tc.want {
|
||||
t.Errorf("Allowed = %v, want %v", got, tc.want)
|
||||
}
|
||||
@@ -49,16 +68,113 @@ func TestAllowed(t *testing.T) {
|
||||
t.Errorf("AllowedInteraction = %v, want %v", got, tc.want)
|
||||
}
|
||||
st := StatusOf(tc.inGuild, tc.member)
|
||||
if st.InBetaGuild != tc.inBeta || st.HasRole != tc.hasRole {
|
||||
t.Errorf("StatusOf = %+v, want in beta server %v, has role %v", st, tc.inBeta, tc.hasRole)
|
||||
if st.ServerEnabled != tc.on || st.HasRole != tc.hasRole {
|
||||
t.Errorf("StatusOf = %+v, want server on %v, tester %v", st, tc.on, tc.hasRole)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptedInServers(t *testing.T) {
|
||||
roles := map[string][]string{testerID: {"1", testerRol}}
|
||||
|
||||
t.Run("a tester in an opted-in server is allowed", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
calls := useLookup(t, roles, nil)
|
||||
if !Allowed(otherGuild, member()) { // roles in this server don't matter
|
||||
t.Error("tester in an opted-in server should be allowed")
|
||||
}
|
||||
if *calls != 1 {
|
||||
t.Errorf("the beta server should be asked once, was asked %d times", *calls)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("the role in the other server doesn't count", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
useLookup(t, map[string][]string{}, nil)
|
||||
if Allowed(otherGuild, member(testerRol)) {
|
||||
t.Error("holding a role with that ID in another server must not make anyone a tester")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a server that didn't opt in is refused, and nothing is looked up", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
calls := useLookup(t, roles, nil)
|
||||
if Allowed("123000000000000001", member()) {
|
||||
t.Error("a server that didn't opt in must be refused")
|
||||
}
|
||||
if *calls != 0 {
|
||||
t.Error("no lookup for a server where beta is off")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a failing lookup fails closed", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
useLookup(t, roles, errors.New("Unknown Member"))
|
||||
if Allowed(otherGuild, member()) {
|
||||
t.Error("an error from Discord must mean no")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no lookup set: testers only qualify in the beta server", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
lookup.Store(nil)
|
||||
if Allowed(otherGuild, member()) {
|
||||
t.Error("without a lookup there is no way to know")
|
||||
}
|
||||
if !Allowed(betaGuild, member(testerRol)) {
|
||||
t.Error("the beta server doesn't need the lookup")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a user without an ID can't be looked up", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
useLookup(t, roles, nil)
|
||||
if Allowed(otherGuild, &discordgo.Member{}) || Allowed(otherGuild, &discordgo.Member{User: &discordgo.User{}}) {
|
||||
t.Error("no user, no access")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no role configured: nobody, even when the server opted in", func(t *testing.T) {
|
||||
Configure(betaGuild, "", []string{otherGuild})
|
||||
useLookup(t, map[string][]string{testerID: {""}}, nil)
|
||||
if Allowed(otherGuild, member()) {
|
||||
t.Error("without a role there are no testers")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bad IDs in the list are dropped", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild, "not-an-id", "", " 5 "})
|
||||
got := Servers()
|
||||
if len(got) != 2 || got[0] != "5" || got[1] != otherGuild {
|
||||
t.Errorf("Servers = %v", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("the beta server isn't listed twice", func(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{betaGuild, otherGuild})
|
||||
if got := Servers(); len(got) != 1 || got[0] != otherGuild {
|
||||
t.Errorf("Servers = %v", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestServerEnabledNeedsNoPerson(t *testing.T) {
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
for guild, want := range map[string]bool{betaGuild: true, otherGuild: true, "123": false, "": false} {
|
||||
if got := ServerEnabled(guild); got != want {
|
||||
t.Errorf("ServerEnabled(%q) = %v, want %v", guild, got, want)
|
||||
}
|
||||
}
|
||||
current.Store(nil)
|
||||
if ServerEnabled(betaGuild) {
|
||||
t.Error("before Configure nothing is on")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotConfiguredAtAll(t *testing.T) {
|
||||
current.Store(nil)
|
||||
if Allowed(betaGuild, member(testerRol)) || GuildID() != "" {
|
||||
if Allowed(betaGuild, member(testerRol)) || GuildID() != "" || len(Servers()) != 0 {
|
||||
t.Error("before Configure nothing is allowed and there's no beta server")
|
||||
}
|
||||
if AllowedInteraction(nil) || AllowedInteraction(&discordgo.InteractionCreate{}) {
|
||||
@@ -67,7 +183,8 @@ func TestNotConfiguredAtAll(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGateRunsTheHandlerOnlyForTesters(t *testing.T) {
|
||||
Configure(betaGuild, testerRol)
|
||||
Configure(betaGuild, testerRol, []string{otherGuild})
|
||||
useLookup(t, map[string][]string{}, nil) // nobody holds the role in the beta server
|
||||
var answered []string
|
||||
orig := respond
|
||||
respond = func(_ *discordgo.Session, _ *discordgo.InteractionCreate, msg string) {
|
||||
@@ -84,9 +201,10 @@ func TestGateRunsTheHandlerOnlyForTesters(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, i := range map[string]*discordgo.InteractionCreate{
|
||||
"no role": interaction(betaGuild, member("1")),
|
||||
"wrong server": interaction("999000000000000001", member(testerRol)),
|
||||
"DM": interaction("", nil),
|
||||
"no role": interaction(betaGuild, member("1")),
|
||||
"opted-in, not a tester": interaction(otherGuild, member(testerRol)),
|
||||
"server not opted in": interaction("123000000000000001", member(testerRol)),
|
||||
"DM": interaction("", nil),
|
||||
} {
|
||||
before := ran
|
||||
h(nil, i)
|
||||
@@ -94,13 +212,20 @@ func TestGateRunsTheHandlerOnlyForTesters(t *testing.T) {
|
||||
t.Errorf("%s: the handler must not run", name)
|
||||
}
|
||||
}
|
||||
if len(answered) != 3 || answered[0] != denied {
|
||||
if len(answered) != 4 || answered[0] != denied {
|
||||
t.Errorf("each refusal is answered with the beta message: %v", answered)
|
||||
}
|
||||
|
||||
useLookup(t, map[string][]string{testerID: {testerRol}}, nil)
|
||||
before := ran
|
||||
h(nil, interaction(otherGuild, member()))
|
||||
if ran != before+1 {
|
||||
t.Error("a tester in an opted-in server runs the handler")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGuardOnItsOwn(t *testing.T) {
|
||||
Configure(betaGuild, testerRol)
|
||||
Configure(betaGuild, testerRol, nil)
|
||||
n := 0
|
||||
orig := respond
|
||||
respond = func(*discordgo.Session, *discordgo.InteractionCreate, string) { n++ }
|
||||
|
||||
Reference in new issue
Block a user