Skip to content

Commit a771327

Browse files
authored
Improve subscriber test reliability (#431)
* Improve subscriber test reliability This tries to produce certificates at a reliable interval so we can accurately measure how "good" our predictions are. * Generate certificates on-demand So we don't run out.
1 parent a06809b commit a771327

File tree

3 files changed

+68
-35
lines changed

3 files changed

+68
-35
lines changed

certexchange/polling/common_test.go

+27-7
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,39 @@ func RandomPowerTable(backend signing.Backend, entries int64) gpbft.PowerEntries
5858
return powerTable
5959
}
6060

61-
func MakeCertificates(t *testing.T, rng *rand.Rand, backend signing.Backend) ([]*certs.FinalityCertificate, gpbft.PowerEntries) {
61+
func MakeCertificates(t *testing.T, rng *rand.Rand, backend signing.Backend) *CertificateGenerator {
6262
powerTable := RandomPowerTable(backend, 10)
6363
tableCid, err := certs.MakePowerTableCID(powerTable)
6464
require.NoError(t, err)
6565

6666
tsg := sim.NewTipSetGenerator(rng.Uint64())
6767
base := &gpbft.TipSet{Epoch: 0, Key: tsg.Sample(), PowerTable: tableCid}
6868

69-
certificates := make([]*certs.FinalityCertificate, 1000)
70-
for i := range certificates {
71-
cert := MakeCertificate(t, rng, tsg, backend, base, uint64(i), powerTable, powerTable)
72-
base = cert.ECChain.Head()
73-
certificates[i] = cert
69+
return &CertificateGenerator{
70+
PowerTable: powerTable,
71+
t: t,
72+
rng: rng,
73+
backend: backend,
74+
tsg: tsg,
75+
base: base,
76+
NextInstance: 0,
7477
}
75-
return certificates, powerTable
78+
}
79+
80+
type CertificateGenerator struct {
81+
PowerTable gpbft.PowerEntries
82+
NextInstance uint64
83+
84+
t *testing.T
85+
rng *rand.Rand
86+
backend signing.Backend
87+
tsg *sim.TipSetGenerator
88+
base *gpbft.TipSet
89+
}
90+
91+
func (cg *CertificateGenerator) MakeCertificate() *certs.FinalityCertificate {
92+
cert := MakeCertificate(cg.t, cg.rng, cg.tsg, cg.backend, cg.base, cg.NextInstance, cg.PowerTable, cg.PowerTable)
93+
cg.base = cert.ECChain.Head()
94+
cg.NextInstance++
95+
return cert
7696
}

certexchange/polling/poller_test.go

+19-20
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestPoller(t *testing.T) {
2020
backend := signing.NewFakeBackend()
2121
rng := rand.New(rand.NewSource(1234))
2222

23-
certificates, powerTable := polling.MakeCertificates(t, rng, backend)
23+
cg := polling.MakeCertificates(t, rng, backend)
2424

2525
ctx, cancel := context.WithCancel(context.Background())
2626
defer cancel()
@@ -37,12 +37,11 @@ func TestPoller(t *testing.T) {
3737

3838
serverDs := ds_sync.MutexWrap(datastore.NewMapDatastore())
3939

40-
serverCs, err := certstore.CreateStore(ctx, serverDs, 0, powerTable)
40+
serverCs, err := certstore.CreateStore(ctx, serverDs, 0, cg.PowerTable)
4141
require.NoError(t, err)
4242

43-
certificatesAdded := 10
44-
for _, cert := range certificates[:certificatesAdded] {
45-
require.NoError(t, serverCs.Put(ctx, cert))
43+
for cg.NextInstance < 10 {
44+
require.NoError(t, serverCs.Put(ctx, cg.MakeCertificate()))
4645
}
4746

4847
server := certexchange.Server{
@@ -55,7 +54,7 @@ func TestPoller(t *testing.T) {
5554
t.Cleanup(func() { require.NoError(t, server.Stop()) })
5655

5756
clientDs := ds_sync.MutexWrap(datastore.NewMapDatastore())
58-
clientCs, err := certstore.CreateStore(ctx, clientDs, 0, powerTable)
57+
clientCs, err := certstore.CreateStore(ctx, clientDs, 0, cg.PowerTable)
5958
require.NoError(t, err)
6059

6160
client := certexchange.Client{
@@ -82,21 +81,21 @@ func TestPoller(t *testing.T) {
8281
res, err := poller.Poll(ctx, serverHost.ID())
8382
require.NoError(t, err)
8483
require.Equal(t, polling.PollHit, res.Status)
85-
require.Equal(t, uint64(certificatesAdded), poller.NextInstance)
84+
require.Equal(t, cg.NextInstance, poller.NextInstance)
8685
}
8786

8887
// If we put a certificate on the client, we should call it a _miss_
8988
{
90-
require.NoError(t, clientCs.Put(ctx, certificates[certificatesAdded]))
89+
cert := cg.MakeCertificate()
90+
require.NoError(t, clientCs.Put(ctx, cert))
9191

9292
res, err := poller.Poll(ctx, serverHost.ID())
9393
require.NoError(t, err)
9494
require.Equal(t, polling.PollMiss, res.Status)
95-
}
9695

97-
// Add that cert to the server.
98-
require.NoError(t, serverCs.Put(ctx, certificates[certificatesAdded]))
99-
certificatesAdded++
96+
// Add that cert to the server.
97+
require.NoError(t, serverCs.Put(ctx, cert))
98+
}
10099

101100
// And now it's a hit!
102101
{
@@ -106,31 +105,31 @@ func TestPoller(t *testing.T) {
106105
}
107106

108107
// Add more than the request maximum (up till the last cert)
109-
for ; certificatesAdded < len(certificates)-1; certificatesAdded++ {
110-
require.NoError(t, serverCs.Put(ctx, certificates[certificatesAdded]))
108+
for cg.NextInstance < 500 {
109+
require.NoError(t, serverCs.Put(ctx, cg.MakeCertificate()))
111110
}
112111

113112
// We should poll multiple times and completely catch up.
114113
{
115114
res, err := poller.Poll(ctx, serverHost.ID())
116115
require.NoError(t, err)
117116
require.Equal(t, polling.PollHit, res.Status)
118-
require.Equal(t, uint64(certificatesAdded), poller.NextInstance)
117+
require.Equal(t, cg.NextInstance, poller.NextInstance)
119118
}
120119

121120
// We catch evil servers!
122121
{
123-
lastCert := certificates[certificatesAdded]
124-
lastCert.Signature = []byte("bad sig")
125-
require.NoError(t, serverCs.Put(ctx, lastCert))
122+
badCert := cg.MakeCertificate()
123+
badCert.Signature = []byte("bad sig")
124+
require.NoError(t, serverCs.Put(ctx, badCert))
126125

127126
res, err := poller.Poll(ctx, serverHost.ID())
128127
require.NoError(t, err)
129128
require.Equal(t, polling.PollIllegal, res.Status)
130129

131130
// And we don't store certificates from them!
132-
require.Equal(t, uint64(certificatesAdded), poller.NextInstance)
133-
_, err = clientCs.Get(ctx, lastCert.GPBFTInstance)
131+
require.Equal(t, badCert.GPBFTInstance, poller.NextInstance)
132+
_, err = clientCs.Get(ctx, badCert.GPBFTInstance)
134133
require.ErrorIs(t, err, certstore.ErrCertNotFound)
135134
}
136135

certexchange/polling/subscriber_test.go

+22-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestSubscriber(t *testing.T) {
2222
backend := signing.NewFakeBackend()
2323
rng := rand.New(rand.NewSource(1234))
2424

25-
certificates, powerTable := polling.MakeCertificates(t, rng, backend)
25+
cg := polling.MakeCertificates(t, rng, backend)
2626

2727
ctx, cancel := context.WithCancel(context.Background())
2828
defer cancel()
@@ -38,7 +38,7 @@ func TestSubscriber(t *testing.T) {
3838
require.NoError(t, err)
3939

4040
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
41-
cs, err := certstore.CreateStore(ctx, ds, 0, powerTable)
41+
cs, err := certstore.CreateStore(ctx, ds, 0, cg.PowerTable)
4242
require.NoError(t, err)
4343

4444
servers[i] = &certexchange.Server{
@@ -56,7 +56,7 @@ func TestSubscriber(t *testing.T) {
5656
}
5757

5858
clientDs := ds_sync.MutexWrap(datastore.NewMapDatastore())
59-
clientCs, err := certstore.CreateStore(ctx, clientDs, 0, powerTable)
59+
clientCs, err := certstore.CreateStore(ctx, clientDs, 0, cg.PowerTable)
6060
require.NoError(t, err)
6161

6262
client := certexchange.Client{
@@ -80,15 +80,29 @@ func TestSubscriber(t *testing.T) {
8080
require.NoError(t, mocknet.ConnectAllButSelf())
8181

8282
liveServers := slices.Clone(servers)
83-
for i := 0; len(liveServers) > 0; i++ {
84-
for _, s := range liveServers {
85-
require.NoError(t, s.Store.Put(ctx, certificates[i]))
83+
lastPoll := time.Now()
84+
i := 0
85+
for len(liveServers) > 0 {
86+
now := time.Now()
87+
timeDelta := now.Sub(lastPoll)
88+
certCount := timeDelta/subscriber.InitialPollInterval + 1
89+
waitTime := certCount * subscriber.InitialPollInterval
90+
for target := i + int(certCount); i < target; i++ {
91+
cert := cg.MakeCertificate()
92+
for _, s := range liveServers {
93+
require.NoError(t, s.Store.Put(ctx, cert))
94+
}
8695
}
8796

97+
polling.MockClock.Add(waitTime)
98+
8899
require.Eventually(t, func() bool {
89-
polling.MockClock.WaitForAllTimers()
90100
latest := clientCs.Latest()
91-
return latest != nil && latest.GPBFTInstance == uint64(i)
101+
if latest != nil && latest.GPBFTInstance == uint64(i-1) {
102+
return true
103+
}
104+
polling.MockClock.WaitForAllTimers()
105+
return false
92106
}, 10*time.Second, time.Millisecond)
93107

94108
// After we settle for a bit, every 4 instances, stop updating 20% of the

0 commit comments

Comments
 (0)