mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			339 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package connmgr
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/libp2p/go-libp2p/core/connmgr"
 | 
						|
	"github.com/libp2p/go-libp2p/core/peer"
 | 
						|
	tu "github.com/libp2p/go-libp2p/core/test"
 | 
						|
 | 
						|
	"github.com/benbjohnson/clock"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
const TestResolution = 50 * time.Millisecond
 | 
						|
 | 
						|
func waitForTag(t *testing.T, mgr *BasicConnMgr, id peer.ID) {
 | 
						|
	t.Helper()
 | 
						|
	require.Eventually(t, func() bool { return mgr.GetTagInfo(id) != nil }, 500*time.Millisecond, 10*time.Millisecond)
 | 
						|
}
 | 
						|
 | 
						|
func TestDecayExpire(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag, err := decay.RegisterDecayingTag("pop", 250*time.Millisecond, connmgr.DecayExpireWhenInactive(1*time.Second), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.NoError(t, tag.Bump(id, 10))
 | 
						|
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
	require.Equal(t, 10, mgr.GetTagInfo(id).Value)
 | 
						|
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 0)
 | 
						|
}
 | 
						|
 | 
						|
func TestMultipleBumps(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, _ := testDecayTracker(t)
 | 
						|
 | 
						|
	tag, err := decay.RegisterDecayingTag("pop", 250*time.Millisecond, connmgr.DecayExpireWhenInactive(1*time.Second), connmgr.BumpSumBounded(10, 20))
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	require.NoError(t, tag.Bump(id, 5))
 | 
						|
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
	require.Equal(t, mgr.GetTagInfo(id).Value, 10)
 | 
						|
 | 
						|
	require.NoError(t, tag.Bump(id, 100))
 | 
						|
	require.Eventually(t, func() bool { return mgr.GetTagInfo(id).Value == 20 }, 100*time.Millisecond, 10*time.Millisecond, "expected tag value to decay to 20")
 | 
						|
}
 | 
						|
 | 
						|
func TestMultipleTagsNoDecay(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, _ := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", 250*time.Millisecond, connmgr.DecayNone(), connmgr.BumpSumBounded(0, 100))
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", 250*time.Millisecond, connmgr.DecayNone(), connmgr.BumpSumBounded(0, 100))
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag3, err := decay.RegisterDecayingTag("foo", 250*time.Millisecond, connmgr.DecayNone(), connmgr.BumpSumBounded(0, 100))
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 100)
 | 
						|
	_ = tag2.Bump(id, 100)
 | 
						|
	_ = tag3.Bump(id, 100)
 | 
						|
	_ = tag1.Bump(id, 100)
 | 
						|
	_ = tag2.Bump(id, 100)
 | 
						|
	_ = tag3.Bump(id, 100)
 | 
						|
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
 | 
						|
	// all tags are upper-bounded, so the score must be 300
 | 
						|
	ti := mgr.GetTagInfo(id)
 | 
						|
	require.Equal(t, ti.Value, 300)
 | 
						|
 | 
						|
	for _, s := range []string{"beep", "bop", "foo"} {
 | 
						|
		if v, ok := ti.Tags[s]; !ok || v != 100 {
 | 
						|
			t.Fatalf("expected tag %s to be 100; was = %d", s, v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestCustomFunctions(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", 250*time.Millisecond, connmgr.DecayFixed(10), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", 100*time.Millisecond, connmgr.DecayFixed(5), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag3, err := decay.RegisterDecayingTag("foo", 50*time.Millisecond, connmgr.DecayFixed(1), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 1000)
 | 
						|
	_ = tag2.Bump(id, 1000)
 | 
						|
	_ = tag3.Bump(id, 1000)
 | 
						|
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
 | 
						|
	// no decay has occurred yet, so score must be 3000.
 | 
						|
	require.Equal(t, 3000, mgr.GetTagInfo(id).Value)
 | 
						|
 | 
						|
	// only tag3 should tick.
 | 
						|
	mockClock.Add(50 * time.Millisecond)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 2999)
 | 
						|
 | 
						|
	// tag3 will tick thrice, tag2 will tick twice.
 | 
						|
	mockClock.Add(150 * time.Millisecond)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 2986)
 | 
						|
 | 
						|
	// tag3 will tick once, tag1 will tick once.
 | 
						|
	mockClock.Add(50 * time.Millisecond)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 2975)
 | 
						|
}
 | 
						|
 | 
						|
func TestMultiplePeers(t *testing.T) {
 | 
						|
	ids := []peer.ID{tu.RandPeerIDFatal(t), tu.RandPeerIDFatal(t), tu.RandPeerIDFatal(t)}
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", 250*time.Millisecond, connmgr.DecayFixed(10), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", 100*time.Millisecond, connmgr.DecayFixed(5), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag3, err := decay.RegisterDecayingTag("foo", 50*time.Millisecond, connmgr.DecayFixed(1), connmgr.BumpSumUnbounded())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	_ = tag1.Bump(ids[0], 1000)
 | 
						|
	_ = tag2.Bump(ids[0], 1000)
 | 
						|
	_ = tag3.Bump(ids[0], 1000)
 | 
						|
 | 
						|
	_ = tag1.Bump(ids[1], 500)
 | 
						|
	_ = tag2.Bump(ids[1], 500)
 | 
						|
	_ = tag3.Bump(ids[1], 500)
 | 
						|
 | 
						|
	_ = tag1.Bump(ids[2], 100)
 | 
						|
	_ = tag2.Bump(ids[2], 100)
 | 
						|
	_ = tag3.Bump(ids[2], 100)
 | 
						|
 | 
						|
	// allow the background goroutine to process bumps.
 | 
						|
	waitFor := 100 * time.Millisecond
 | 
						|
	tick := 10 * time.Millisecond
 | 
						|
	if os.Getenv("CI") != "" {
 | 
						|
		waitFor *= 10
 | 
						|
		tick *= 10
 | 
						|
	}
 | 
						|
 | 
						|
	require.Eventually(t, func() bool {
 | 
						|
		return mgr.GetTagInfo(ids[0]) != nil && mgr.GetTagInfo(ids[1]) != nil && mgr.GetTagInfo(ids[2]) != nil
 | 
						|
	}, waitFor, tick)
 | 
						|
 | 
						|
	mockClock.Add(3 * time.Second)
 | 
						|
 | 
						|
	waitFor = 500 * time.Millisecond
 | 
						|
	if os.Getenv("CI") != "" {
 | 
						|
		waitFor *= 10
 | 
						|
	}
 | 
						|
 | 
						|
	require.Eventually(t, func() bool { return mgr.GetTagInfo(ids[0]).Value == 2670 }, waitFor, tick)
 | 
						|
	require.Equal(t, 1170, mgr.GetTagInfo(ids[1]).Value)
 | 
						|
	require.Equal(t, 40, mgr.GetTagInfo(ids[2]).Value)
 | 
						|
}
 | 
						|
 | 
						|
func eventuallyEqual(t *testing.T, f func() int, val int) {
 | 
						|
	t.Helper()
 | 
						|
	require.Eventually(t, func() bool {
 | 
						|
		v := f()
 | 
						|
		if v == val {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
		t.Log("f() was", v, "expected", val, "retrying...")
 | 
						|
		return false
 | 
						|
	}, 1*time.Second, 10*time.Millisecond)
 | 
						|
}
 | 
						|
 | 
						|
func TestLinearDecayOverwrite(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", 250*time.Millisecond, connmgr.DecayLinear(0.5), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 1000)
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 1000)
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 500)
 | 
						|
 | 
						|
	mockClock.Add(250 * time.Millisecond)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 250)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 1000)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Value }, 1000)
 | 
						|
}
 | 
						|
 | 
						|
func TestResolutionMisaligned(t *testing.T) {
 | 
						|
	var (
 | 
						|
		id                    = tu.RandPeerIDFatal(t)
 | 
						|
		mgr, decay, mockClock = testDecayTracker(t)
 | 
						|
		require               = require.New(t)
 | 
						|
	)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", time.Duration(float64(TestResolution)*1.4), connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(err)
 | 
						|
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", time.Duration(float64(TestResolution)*2.4), connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(err)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 1000)
 | 
						|
	_ = tag2.Bump(id, 1000)
 | 
						|
	// allow the background goroutine to process bumps.
 | 
						|
	<-time.After(500 * time.Millisecond)
 | 
						|
 | 
						|
	// first tick.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Tags["beep"] }, 1000)
 | 
						|
	require.Equal(1000, mgr.GetTagInfo(id).Tags["bop"])
 | 
						|
 | 
						|
	// next tick; tag1 would've ticked.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Tags["beep"] }, 999)
 | 
						|
	require.Equal(1000, mgr.GetTagInfo(id).Tags["bop"])
 | 
						|
 | 
						|
	// next tick; tag1 would've ticked twice, tag2 once.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Tags["beep"] }, 998)
 | 
						|
	require.Equal(999, mgr.GetTagInfo(id).Tags["bop"])
 | 
						|
 | 
						|
	require.Equal(1997, mgr.GetTagInfo(id).Value)
 | 
						|
}
 | 
						|
 | 
						|
func TestTagRemoval(t *testing.T) {
 | 
						|
	id1, id2 := tu.RandPeerIDFatal(t), tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", TestResolution, connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", TestResolution, connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	// id1 has both tags; id2 only has the first tag.
 | 
						|
	_ = tag1.Bump(id1, 1000)
 | 
						|
	_ = tag2.Bump(id1, 1000)
 | 
						|
	_ = tag1.Bump(id2, 1000)
 | 
						|
 | 
						|
	waitForTag(t, mgr, id1)
 | 
						|
	waitForTag(t, mgr, id2)
 | 
						|
 | 
						|
	// first tick.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id1).Tags["beep"] }, 999)
 | 
						|
	require.Equal(t, 999, mgr.GetTagInfo(id1).Tags["bop"])
 | 
						|
	require.Equal(t, 999, mgr.GetTagInfo(id2).Tags["beep"])
 | 
						|
 | 
						|
	require.Equal(t, 999*2, mgr.GetTagInfo(id1).Value)
 | 
						|
	require.Equal(t, 999, mgr.GetTagInfo(id2).Value)
 | 
						|
 | 
						|
	// remove tag1 from p1.
 | 
						|
	require.NoError(t, tag1.Remove(id1))
 | 
						|
 | 
						|
	// next tick. both peers only have 1 tag, both at 998 value.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	require.Eventually(t, func() bool { return mgr.GetTagInfo(id1).Tags["beep"] == 0 }, 500*time.Millisecond, 10*time.Millisecond)
 | 
						|
	require.Equal(t, 998, mgr.GetTagInfo(id1).Tags["bop"])
 | 
						|
	require.Equal(t, 998, mgr.GetTagInfo(id2).Tags["beep"])
 | 
						|
 | 
						|
	require.Equal(t, 998, mgr.GetTagInfo(id1).Value)
 | 
						|
	require.Equal(t, 998, mgr.GetTagInfo(id2).Value)
 | 
						|
 | 
						|
	// remove tag1 from p1 again; no error.
 | 
						|
	require.NoError(t, tag1.Remove(id1))
 | 
						|
}
 | 
						|
 | 
						|
func TestTagClosure(t *testing.T) {
 | 
						|
	id := tu.RandPeerIDFatal(t)
 | 
						|
	mgr, decay, mockClock := testDecayTracker(t)
 | 
						|
 | 
						|
	tag1, err := decay.RegisterDecayingTag("beep", TestResolution, connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(t, err)
 | 
						|
	tag2, err := decay.RegisterDecayingTag("bop", TestResolution, connmgr.DecayFixed(1), connmgr.BumpOverwrite())
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	_ = tag1.Bump(id, 1000)
 | 
						|
	_ = tag2.Bump(id, 1000)
 | 
						|
	waitForTag(t, mgr, id)
 | 
						|
 | 
						|
	// nothing has happened.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Tags["beep"] }, 999)
 | 
						|
	require.Equal(t, 999, mgr.GetTagInfo(id).Tags["bop"])
 | 
						|
	require.Equal(t, 999*2, mgr.GetTagInfo(id).Value)
 | 
						|
 | 
						|
	// next tick; tag1 would've ticked.
 | 
						|
	mockClock.Add(TestResolution)
 | 
						|
	eventuallyEqual(t, func() int { return mgr.GetTagInfo(id).Tags["beep"] }, 998)
 | 
						|
	require.Equal(t, 998, mgr.GetTagInfo(id).Tags["bop"])
 | 
						|
	require.Equal(t, 998*2, mgr.GetTagInfo(id).Value)
 | 
						|
 | 
						|
	// close the tag.
 | 
						|
	require.NoError(t, tag1.Close())
 | 
						|
 | 
						|
	// allow the background goroutine to process the closure.
 | 
						|
	require.Eventually(t, func() bool { return mgr.GetTagInfo(id).Value == 998 }, 500*time.Millisecond, 10*time.Millisecond)
 | 
						|
 | 
						|
	// a second closure should not error.
 | 
						|
	require.NoError(t, tag1.Close())
 | 
						|
 | 
						|
	// bumping a tag after it's been closed should error.
 | 
						|
	require.Error(t, tag1.Bump(id, 5))
 | 
						|
}
 | 
						|
 | 
						|
func testDecayTracker(tb testing.TB) (*BasicConnMgr, connmgr.Decayer, *clock.Mock) {
 | 
						|
	mockClock := clock.NewMock()
 | 
						|
	cfg := &DecayerCfg{
 | 
						|
		Resolution: TestResolution,
 | 
						|
		Clock:      mockClock,
 | 
						|
	}
 | 
						|
 | 
						|
	mgr, err := NewConnManager(10, 10, WithGracePeriod(time.Second), DecayerConfig(cfg))
 | 
						|
	require.NoError(tb, err)
 | 
						|
	decay, ok := connmgr.SupportsDecay(mgr)
 | 
						|
	if !ok {
 | 
						|
		tb.Fatalf("connmgr does not support decay")
 | 
						|
	}
 | 
						|
	tb.Cleanup(func() {
 | 
						|
		mgr.Close()
 | 
						|
		decay.Close()
 | 
						|
	})
 | 
						|
 | 
						|
	return mgr, decay, mockClock
 | 
						|
}
 |