github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/webhook/webhook_test.go (about)

     1  package webhook
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/http"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	"go.uber.org/atomic"
    13  
    14  	"github.com/whoyao/protocol/auth"
    15  	"github.com/whoyao/protocol/livekit"
    16  )
    17  
    18  const (
    19  	apiKey               = "mykey"
    20  	apiSecret            = "mysecret"
    21  	testAddr             = ":8765"
    22  	testUrl              = "http://localhost:8765"
    23  	webhookCheckInterval = 100 * time.Millisecond
    24  )
    25  
    26  var authProvider = auth.NewSimpleKeyProvider(
    27  	apiKey, apiSecret,
    28  )
    29  
    30  func TestWebHook(t *testing.T) {
    31  	s := newServer(testAddr)
    32  	require.NoError(t, s.Start())
    33  	defer s.Stop()
    34  
    35  	notifier := NewDefaultNotifier(apiKey, apiSecret, []string{testUrl})
    36  
    37  	t.Run("test event payload", func(t *testing.T) {
    38  		event := &livekit.WebhookEvent{
    39  			Event: EventTrackPublished,
    40  			Participant: &livekit.ParticipantInfo{
    41  				Identity: "test",
    42  			},
    43  			Track: &livekit.TrackInfo{
    44  				Sid: "TR_abcde",
    45  			},
    46  		}
    47  
    48  		wg := sync.WaitGroup{}
    49  		wg.Add(1)
    50  		s.handler = func(r *http.Request) {
    51  			defer wg.Done()
    52  			decodedEvent, err := ReceiveWebhookEvent(r, authProvider)
    53  			require.NoError(t, err)
    54  
    55  			require.EqualValues(t, event, decodedEvent)
    56  		}
    57  		require.NoError(t, notifier.QueueNotify(context.Background(), event))
    58  		wg.Wait()
    59  	})
    60  
    61  }
    62  
    63  func TestURLNotifierDropped(t *testing.T) {
    64  	s := newServer(testAddr)
    65  	require.NoError(t, s.Start())
    66  	defer s.Stop()
    67  
    68  	urlNotifier := newTestNotifier()
    69  	defer urlNotifier.Stop(true)
    70  	totalDropped := atomic.Int32{}
    71  	totalReceived := atomic.Int32{}
    72  	s.handler = func(r *http.Request) {
    73  		decodedEvent, err := ReceiveWebhookEvent(r, authProvider)
    74  		require.NoError(t, err)
    75  		totalReceived.Inc()
    76  		totalDropped.Add(decodedEvent.NumDropped)
    77  	}
    78  	// send multiple notifications
    79  	for i := 0; i < 10; i++ {
    80  		_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted})
    81  		_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventParticipantJoined})
    82  		_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished})
    83  	}
    84  
    85  	time.Sleep(webhookCheckInterval)
    86  
    87  	require.Equal(t, int32(30), totalDropped.Load()+totalReceived.Load())
    88  	// at least one request dropped
    89  	require.Less(t, int32(0), totalDropped.Load())
    90  }
    91  
    92  func TestURLNotifierLifecycle(t *testing.T) {
    93  	s := newServer(testAddr)
    94  	require.NoError(t, s.Start())
    95  	defer s.Stop()
    96  
    97  	t.Run("start/stop without use", func(t *testing.T) {
    98  		urlNotifier := newTestNotifier()
    99  		urlNotifier.Stop(false)
   100  	})
   101  
   102  	t.Run("stop allowing to drain", func(t *testing.T) {
   103  		urlNotifier := newTestNotifier()
   104  		numCalled := atomic.Int32{}
   105  		s.handler = func(r *http.Request) {
   106  			numCalled.Inc()
   107  		}
   108  		for i := 0; i < 10; i++ {
   109  			_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted})
   110  			_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished})
   111  		}
   112  		urlNotifier.Stop(false)
   113  		require.Eventually(t, func() bool { return numCalled.Load() == 20 }, 5*time.Second, webhookCheckInterval)
   114  	})
   115  
   116  	t.Run("force stop", func(t *testing.T) {
   117  		urlNotifier := newTestNotifier()
   118  		numCalled := atomic.Int32{}
   119  		s.handler = func(r *http.Request) {
   120  			numCalled.Inc()
   121  		}
   122  		for i := 0; i < 10; i++ {
   123  			_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted})
   124  			_ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished})
   125  		}
   126  		urlNotifier.Stop(true)
   127  		time.Sleep(time.Second)
   128  		require.Greater(t, int32(20), numCalled.Load())
   129  	})
   130  }
   131  
   132  func newTestNotifier() *URLNotifier {
   133  	return NewURLNotifier(URLNotifierParams{
   134  		QueueSize: 20,
   135  		URL:       testUrl,
   136  		APIKey:    apiKey,
   137  		APISecret: apiSecret,
   138  	})
   139  }
   140  
   141  type testServer struct {
   142  	handler func(r *http.Request)
   143  	server  *http.Server
   144  }
   145  
   146  func newServer(addr string) *testServer {
   147  	s := &testServer{}
   148  	s.server = &http.Server{
   149  		Addr:    addr,
   150  		Handler: s,
   151  	}
   152  	return s
   153  }
   154  
   155  func (s *testServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   156  	if s.handler != nil {
   157  		s.handler(r)
   158  	}
   159  }
   160  
   161  func (s *testServer) Start() error {
   162  	l, err := net.Listen("tcp", s.server.Addr)
   163  	if err != nil {
   164  		return err
   165  	}
   166  	go s.server.Serve(l)
   167  	return nil
   168  }
   169  
   170  func (s *testServer) Stop() {
   171  	_ = s.server.Shutdown(context.Background())
   172  }