repositories / bugabinga.net
bugabinga.net
personal infrastructure for bugabinga!
owned by admin
services/luci/internal/web/shortid_test.go
Rawpackage web
import (
"math/rand/v2"
"reflect"
"strconv"
"strings"
"testing"
"bugabinga.net/luci/internal/history"
"bugabinga.net/luci/internal/inbox"
"bugabinga.net/luci/internal/proquint"
"bugabinga.net/luci/internal/runstate"
)
func TestBuildShortenerMatchesReference(t *testing.T) {
tests := []struct {
name string
events []history.Event
pending []inbox.Pending
active []runstate.Active
wantRunShort map[string]string
wantNoRunShort []string
wantRevShort map[string]string
wantNoRevShort []string
}{
{
name: "parse failures and zero aliases",
events: []history.Event{
{RunID: "0", Rev: "abcd"},
{RunID: "+0", Rev: "abc"},
{RunID: "not-a-number", Rev: "abcd0"},
},
pending: []inbox.Pending{{ID: "9223372036854775808"}},
active: []runstate.Active{{RunID: "-0", Rev: "abce"}},
wantNoRunShort: []string{"0", "+0", "-0", "not-a-number", "9223372036854775808"},
wantRevShort: map[string]string{"abcd0": "abcd0", "abce": "abce"},
wantNoRevShort: []string{"abc"},
},
{
name: "negative ids and block boundaries",
events: []history.Event{
{RunID: "0"},
{RunID: "1"},
{RunID: "65536"},
{RunID: "-1"},
},
wantRunShort: map[string]string{
"0": proquint.Encode(0),
"1": proquint.Encode(1),
"65536": proquint.Encode(65536)[:17],
"-1": proquint.Encode(-1)[:5],
},
},
{
name: "duplicate equivalent encodings",
events: []history.Event{
{RunID: "1"},
{RunID: "0001"},
},
pending: []inbox.Pending{{ID: "+1"}},
wantNoRunShort: []string{"1", "0001", "+1"},
},
{
name: "revision boundaries",
events: []history.Event{
{RunID: "1", Rev: "abc"},
{RunID: "2", Rev: "abcd"},
{RunID: "3", Rev: "abcd0"},
{RunID: "4", Rev: "abce"},
{RunID: "5", Rev: ""},
},
wantRevShort: map[string]string{"abcd0": "abcd0", "abce": "abce"},
wantNoRevShort: []string{"abc", "abcd"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
want := referenceShortener(test.events, test.pending, test.active)
for range 100 {
if got := buildShortener(test.events, test.pending, test.active); !reflect.DeepEqual(got, want) {
t.Fatalf("shortener=%#v want %#v", got, want)
}
}
got := buildShortener(test.events, test.pending, test.active)
for id, short := range test.wantRunShort {
if got.runShort[id] != short {
t.Fatalf("run id %q shortened to %q want %q", id, got.runShort[id], short)
}
}
for _, id := range test.wantNoRunShort {
if _, ok := got.runShort[id]; ok {
t.Fatalf("run id %q unexpectedly shortened to %q", id, got.runShort[id])
}
}
for rev, short := range test.wantRevShort {
if got.revShort[rev] != short {
t.Fatalf("revision %q shortened to %q want %q", rev, got.revShort[rev], short)
}
}
for _, rev := range test.wantNoRevShort {
if _, ok := got.revShort[rev]; ok {
t.Fatalf("revision %q unexpectedly shortened to %q", rev, got.revShort[rev])
}
}
})
}
}
func TestBuildShortenerMatchesReferenceRandomized(t *testing.T) {
random := rand.New(rand.NewPCG(20260927, 1))
for set := range 50 {
events, pending, active := randomShortenerInputs(random, 1+random.IntN(80))
want := referenceShortener(events, pending, active)
for range 10 {
if got := buildShortener(events, pending, active); !reflect.DeepEqual(got, want) {
t.Fatalf("set %d: shortener=%#v want %#v", set, got, want)
}
}
}
}
func randomShortenerInputs(random *rand.Rand, count int) ([]history.Event, []inbox.Pending, []runstate.Active) {
events := make([]history.Event, 0, count)
pending := make([]inbox.Pending, 0, count)
active := make([]runstate.Active, 0, count)
for i := range count {
id := randomShortenerID(random, i)
rev := randomShortenerRevision(random, i)
switch i % 3 {
case 0:
events = append(events, history.Event{RunID: id, Rev: rev})
case 1:
pending = append(pending, inbox.Pending{ID: id})
case 2:
active = append(active, runstate.Active{RunID: id, Rev: rev})
}
}
return events, pending, active
}
func randomShortenerID(random *rand.Rand, index int) string {
switch index % 8 {
case 0:
return strconv.FormatInt(random.Int64(), 10)
case 1:
return "0"
case 2:
return "+0"
case 3:
return "-0"
case 4:
return "invalid-" + strconv.Itoa(random.IntN(8))
case 5:
return "9223372036854775808"
case 6:
return "000" + strconv.Itoa(random.IntN(4))
default:
return strconv.FormatInt(-random.Int64N(1<<32), 10)
}
}
func randomShortenerRevision(random *rand.Rand, index int) string {
length := index % 9
if length == 0 {
return ""
}
const hex = "0123456789abcdef"
var text strings.Builder
for range length {
text.WriteByte(hex[random.IntN(len(hex))])
}
return text.String()
}
// referenceShortener preserves buildShortener's pre-optimization algorithm.
func referenceShortener(events []history.Event, pending []inbox.Pending, active []runstate.Active) shortener {
ids := map[string]bool{}
for _, event := range events {
ids[event.RunID] = true
}
for _, current := range pending {
ids[current.ID] = true
}
for _, current := range active {
ids[current.RunID] = true
}
revs := map[string]bool{}
for _, event := range events {
if event.Rev != "" {
revs[event.Rev] = true
}
}
for _, current := range active {
if current.Rev != "" {
revs[current.Rev] = true
}
}
runShort := map[string]string{}
for id := range ids {
blocks := strings.Split(proquint.Encode(parseID(id)), "-")
for keep := 1; keep <= len(blocks); keep++ {
prefix := strings.Join(blocks[:keep], "-")
if referenceUniquePrefix(ids, prefix) {
runShort[id] = prefix
break
}
}
}
revShort := map[string]string{}
for rev := range revs {
for length := 4; length <= len(rev); length++ {
if referenceUniqueHexPrefix(revs, rev[:length]) {
revShort[rev] = rev[:length]
break
}
}
}
return shortener{runShort: runShort, revShort: revShort}
}
func referenceUniquePrefix(ids map[string]bool, prefix string) bool {
count := 0
for id := range ids {
if strings.HasPrefix(proquint.Encode(parseID(id)), prefix) {
count++
}
}
return count == 1
}
func referenceUniqueHexPrefix(revs map[string]bool, prefix string) bool {
count := 0
for rev := range revs {
if strings.HasPrefix(rev, prefix) {
count++
}
}
return count == 1
}