Path: blob/dev/pkg/protocols/common/protocolstate/memguardian_test.go
2843 views
package protocolstate12import (3"context"4"testing"5"time"67"github.com/projectdiscovery/utils/memguardian"8"github.com/stretchr/testify/require"9"github.com/tarunKoyalwar/goleak"10)1112// TestMemGuardianGoroutineLeak tests that MemGuardian properly cleans up goroutines13func TestMemGuardianGoroutineLeak(t *testing.T) {14defer goleak.VerifyNone(t,15goleak.IgnoreAnyContainingPkg("go.opencensus.io/stats/view"),16goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),17goleak.IgnoreAnyContainingPkg("github.com/go-rod/rod"),18goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/server"),19goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),20)2122// Initialize memguardian if not already initialized23if memguardian.DefaultMemGuardian == nil {24var err error25memguardian.DefaultMemGuardian, err = memguardian.New()26require.NoError(t, err, "Failed to initialize memguardian")27}2829t.Run("StartAndStopMemGuardian", func(t *testing.T) {30// Test that starting and stopping memguardian doesn't leak goroutines31ctx := context.Background()3233// Start MemGuardian34StartActiveMemGuardian(ctx)35require.NotNil(t, memTimer, "memTimer should be initialized")36require.NotNil(t, cancelFunc, "cancelFunc should be initialized")3738// Give it a moment to start39time.Sleep(10 * time.Millisecond)4041// Stop MemGuardian42StopActiveMemGuardian()4344// Give goroutine time to exit45time.Sleep(20 * time.Millisecond)4647// Verify cleanup48require.Nil(t, memTimer, "memTimer should be nil after stop")49require.Nil(t, cancelFunc, "cancelFunc should be nil after stop")50})5152t.Run("MultipleStartStop", func(t *testing.T) {53// Test multiple start/stop cycles54for i := 0; i < 3; i++ {55ctx := context.Background()56StartActiveMemGuardian(ctx)57time.Sleep(5 * time.Millisecond)58StopActiveMemGuardian()59time.Sleep(10 * time.Millisecond)60}61})6263t.Run("ContextCancellation", func(t *testing.T) {64// Test that context cancellation properly stops the goroutine65ctx, cancel := context.WithCancel(context.Background())6667StartActiveMemGuardian(ctx)68require.NotNil(t, memTimer, "memTimer should be initialized")6970// Cancel context to trigger goroutine exit71cancel()7273// Give it time to process cancellation74time.Sleep(20 * time.Millisecond)7576// Clean up77StopActiveMemGuardian()78time.Sleep(10 * time.Millisecond)79})8081t.Run("IdempotentStart", func(t *testing.T) {82// Test that multiple starts don't create multiple goroutines83ctx := context.Background()8485StartActiveMemGuardian(ctx)86firstTimer := memTimer8788// Start again - should be idempotent89StartActiveMemGuardian(ctx)90require.Equal(t, firstTimer, memTimer, "memTimer should be the same")91require.NotNil(t, cancelFunc, "cancelFunc should still be set")9293StopActiveMemGuardian()94time.Sleep(10 * time.Millisecond)95})96}9798// TestMemGuardianReset tests resetting global state99func TestMemGuardianReset(t *testing.T) {100defer goleak.VerifyNone(t,101goleak.IgnoreAnyContainingPkg("go.opencensus.io/stats/view"),102goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),103goleak.IgnoreAnyContainingPkg("github.com/go-rod/rod"),104goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/interactsh/pkg/server"),105goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),106)107108// Ensure clean state109StopActiveMemGuardian()110time.Sleep(20 * time.Millisecond) // Allow any existing goroutines to exit111112// Test that we can start after stop113ctx := context.Background()114StartActiveMemGuardian(ctx)115116// Verify it started117require.NotNil(t, memTimer, "memTimer should be initialized after restart")118119// Clean up120StopActiveMemGuardian()121time.Sleep(10 * time.Millisecond) // Allow cleanup122}123124125