Something went wrong. Try again.
An ATProto Powered Reputation Network
Something went wrong. Try again.
4.0 kB · 90 lines
Go
at master
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091package appview
import ( "context" "errors" "path/filepath" "provenance/internal/domain" "provenance/internal/storage" "provenance/internal/trust" "provenance/internal/trust/algorithms" "testing" "time")
type listRepository struct { repository snapshot domain.ListSnapshot err error reads int}
func (r *listRepository) ListSnapshot(context.Context, string) (domain.ListSnapshot, error) { return r.snapshot, r.err}func (r *listRepository) ListMembers(context.Context, string) (domain.ListData, error) { r.reads++ return r.snapshot.Lists[0], r.err}
func TestListService(t *testing.T) { ctx := context.Background() const owner = "did:plc:listowner" const uri = "at://" + owner + "/app.bsky.graph.list/mod" const date = "2026-10-09T00:00:00Z" for _, algorithm := range []trust.Algorithm{algorithms.Optimistic{}, algorithms.ShortestPath{}} { t.Run(algorithm.Describe().Name, func(t *testing.T) { store, err := storage.OpenWithSoft(filepath.Join(t.TempDir(), "lists.db"), domain.SoftParticipantLists) if err != nil { t.Fatal(err) } defer store.Close() repo := &listRepository{snapshot: domain.ListSnapshot{Blocks: []domain.ListRecord{{Author: alice, Source: domain.ListBlockCollection, RecordKey: "block", ListURI: uri, CreatedAt: date}}, Lists: []domain.ListData{{URI: uri, TimeUS: 100, Records: []domain.ListRecord{{Author: owner, Source: domain.ListCollection, RecordKey: "mod", ListURI: uri, Purpose: domain.ModerationList, CreatedAt: date}, {Author: owner, Source: domain.ListItemCollection, RecordKey: "member", ListURI: uri, Subject: bob, CreatedAt: date}}}}}} duplicate := repo.snapshot.Blocks[0] duplicate.RecordKey = "block-2" repo.snapshot.Blocks = append(repo.snapshot.Blocks, duplicate) s := NewWithOptions(store, repo, trust.Limits{States: 100, Edges: 100, Penalty: .1}, Options{Trust: algorithm, SoftMode: domain.SoftParticipantLists}) if err := s.Join(ctx, alice); err != nil { t.Fatal(err) } got, err := s.Reputation(ctx, alice, bob, "", domain.Default) if err != nil || got.Status != trust.CalculatedStatus || got.Score == nil || *got.Score != -.5 || got.PathScores[1].ListURI != uri || got.PathScores[1].Source != domain.ListBlockCollection { t.Fatalf("blocked list trust: %+v %v", got, err) } rep, err := s.RelativeReputation(ctx, alice, bob, "", domain.Default, 1) if err != nil || rep.Score != -.5 || rep.MeanScore != -.5 { t.Fatalf("blocked list reputation: %+v %v", rep, err) } wanted, err := s.wanted(ctx, owner, time.Now().UnixMicro()) if err != nil || !wanted { t.Fatalf("nonparticipant list owner: %v %v", wanted, err) } stamp := time.Now().Add(time.Second).UnixMicro() if err := s.Apply(ctx, domain.Change{Kind: domain.RecordChange, DID: owner, Source: domain.ListItemCollection, RecordKey: "member", TimeUS: stamp}); err != nil { t.Fatal(err) } got, err = s.Reputation(ctx, alice, bob, "", domain.Default) if err != nil || got.Status != trust.UnknownStatus { t.Fatalf("stale list path: %+v %v", got, err) } repo.err = errors.New("owner unavailable") block := repo.snapshot.Blocks[0] err = s.Apply(ctx, domain.Change{Kind: domain.RecordChange, DID: alice, Source: block.Source, RecordKey: block.RecordKey, ListRecord: &block, TimeUS: stamp + 1}) if !errors.Is(err, repo.err) { t.Fatalf("hydration error ignored: %v", err) } repo.err = nil repo.snapshot.Lists[0].TimeUS = stamp + 2 if err := s.Apply(ctx, domain.Change{Kind: domain.RecordChange, DID: alice, Source: block.Source, RecordKey: block.RecordKey, ListRecord: &block, TimeUS: stamp + 3}); err != nil { t.Fatal(err) } reads := repo.reads if err := s.Apply(ctx, domain.Change{Kind: domain.RecordChange, DID: alice, Source: block.Source, RecordKey: block.RecordKey, ListRecord: &block, TimeUS: stamp + 3}); err != nil { t.Fatal(err) } if repo.reads != reads { t.Fatal("replay fetched list again") } }) }}