1package engine
2
3import (
4 "bytes"
5 "context"
6 "fmt"
7 "testing"
8
9 appbsky "github.com/bluesky-social/indigo/api/bsky"
10 "github.com/bluesky-social/indigo/atproto/identity"
11 "github.com/bluesky-social/indigo/atproto/syntax"
12 "github.com/bluesky-social/indigo/automod/countstore"
13
14 "github.com/stretchr/testify/assert"
15)
16
17func alwaysTakedownRecordRule(c *RecordContext) error {
18 c.TakedownRecord()
19 return nil
20}
21
22func alwaysReportRecordRule(c *RecordContext) error {
23 c.ReportRecord(ReportReasonOther, "test report")
24 return nil
25}
26
27func TestTakedownCircuitBreaker(t *testing.T) {
28 assert := assert.New(t)
29 ctx := context.Background()
30 eng := EngineTestFixture()
31 dir := identity.NewMockDirectory()
32 eng.Directory = &dir
33 // note that this is a record-level action, not account-level
34 eng.Rules = RuleSet{
35 RecordRules: []RecordRuleFunc{
36 alwaysTakedownRecordRule,
37 },
38 }
39
40 cid1 := syntax.CID("cid123")
41 p1 := appbsky.FeedPost{Text: "some post blah"}
42 p1buf := new(bytes.Buffer)
43 assert.NoError(p1.MarshalCBOR(p1buf))
44 p1cbor := p1buf.Bytes()
45
46 // generate double the quote of events; expect to only count the quote worth of actions
47 for i := 0; i < 2*eng.Config.QuotaModTakedownDay; i++ {
48 ident := identity.Identity{
49 DID: syntax.DID(fmt.Sprintf("did:plc:abc%d", i)),
50 Handle: syntax.Handle("handle.example.com"),
51 }
52 dir.Insert(ident)
53 op := RecordOp{
54 Action: CreateOp,
55 DID: ident.DID,
56 Collection: syntax.NSID("app.bsky.feed.post"),
57 RecordKey: syntax.RecordKey("abc123"),
58 CID: &cid1,
59 RecordCBOR: p1cbor,
60 }
61 assert.NoError(eng.ProcessRecordOp(ctx, op))
62 }
63
64 takedowns, err := eng.Counters.GetCount(ctx, "automod-quota", "takedown", countstore.PeriodDay)
65 assert.NoError(err)
66 assert.Equal(eng.Config.QuotaModTakedownDay, takedowns)
67
68 reports, err := eng.Counters.GetCount(ctx, "automod-quota", "report", countstore.PeriodDay)
69 assert.NoError(err)
70 assert.Equal(0, reports)
71}
72
73func TestReportCircuitBreaker(t *testing.T) {
74 assert := assert.New(t)
75 ctx := context.Background()
76 eng := EngineTestFixture()
77 dir := identity.NewMockDirectory()
78 eng.Directory = &dir
79 eng.Rules = RuleSet{
80 RecordRules: []RecordRuleFunc{
81 alwaysReportRecordRule,
82 },
83 }
84
85 cid1 := syntax.CID("cid123")
86 p1 := appbsky.FeedPost{Text: "some post blah"}
87 p1buf := new(bytes.Buffer)
88 assert.NoError(p1.MarshalCBOR(p1buf))
89 p1cbor := p1buf.Bytes()
90
91 // generate double the quota of events; expect to only count the quota worth of actions
92 for i := 0; i < 2*eng.Config.QuotaModReportDay; i++ {
93 ident := identity.Identity{
94 DID: syntax.DID(fmt.Sprintf("did:plc:abc%d", i)),
95 Handle: syntax.Handle("handle.example.com"),
96 }
97 dir.Insert(ident)
98 op := RecordOp{
99 Action: CreateOp,
100 DID: ident.DID,
101 Collection: syntax.NSID("app.bsky.feed.post"),
102 RecordKey: syntax.RecordKey("abc123"),
103 CID: &cid1,
104 RecordCBOR: p1cbor,
105 }
106 assert.NoError(eng.ProcessRecordOp(ctx, op))
107 }
108
109 takedowns, err := eng.Counters.GetCount(ctx, "automod-quota", "takedown", countstore.PeriodDay)
110 assert.NoError(err)
111 assert.Equal(0, takedowns)
112
113 reports, err := eng.Counters.GetCount(ctx, "automod-quota", "report", countstore.PeriodDay)
114 assert.NoError(err)
115 assert.Equal(eng.Config.QuotaModReportDay, reports)
116}