github.com/livekit/protocol@v1.16.1-0.20240517185851-47e4c6bba773/webhook/webhook_test.go (about) 1 // Copyright 2023 LiveKit, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package webhook 16 17 import ( 18 "context" 19 "net" 20 "net/http" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/require" 26 "go.uber.org/atomic" 27 28 "github.com/livekit/protocol/auth" 29 "github.com/livekit/protocol/livekit" 30 ) 31 32 const ( 33 apiKey = "mykey" 34 apiSecret = "mysecret" 35 testAddr = ":8765" 36 testUrl = "http://localhost:8765" 37 webhookCheckInterval = 100 * time.Millisecond 38 ) 39 40 var authProvider = auth.NewSimpleKeyProvider( 41 apiKey, apiSecret, 42 ) 43 44 func TestWebHook(t *testing.T) { 45 s := newServer(testAddr) 46 require.NoError(t, s.Start()) 47 defer s.Stop() 48 49 notifier := NewDefaultNotifier(apiKey, apiSecret, []string{testUrl}) 50 51 t.Run("test event payload", func(t *testing.T) { 52 event := &livekit.WebhookEvent{ 53 Event: EventTrackPublished, 54 Participant: &livekit.ParticipantInfo{ 55 Identity: "test", 56 }, 57 Track: &livekit.TrackInfo{ 58 Sid: "TR_abcde", 59 }, 60 } 61 62 wg := sync.WaitGroup{} 63 wg.Add(1) 64 s.handler = func(r *http.Request) { 65 defer wg.Done() 66 decodedEvent, err := ReceiveWebhookEvent(r, authProvider) 67 require.NoError(t, err) 68 69 require.EqualValues(t, event, decodedEvent) 70 } 71 require.NoError(t, notifier.QueueNotify(context.Background(), event)) 72 wg.Wait() 73 }) 74 75 } 76 77 func TestURLNotifierDropped(t *testing.T) { 78 s := newServer(testAddr) 79 require.NoError(t, s.Start()) 80 defer s.Stop() 81 82 urlNotifier := newTestNotifier() 83 defer urlNotifier.Stop(true) 84 totalDropped := atomic.Int32{} 85 totalReceived := atomic.Int32{} 86 s.handler = func(r *http.Request) { 87 decodedEvent, err := ReceiveWebhookEvent(r, authProvider) 88 require.NoError(t, err) 89 totalReceived.Inc() 90 totalDropped.Add(decodedEvent.NumDropped) 91 } 92 // send multiple notifications 93 for i := 0; i < 10; i++ { 94 _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted}) 95 _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventParticipantJoined}) 96 _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished}) 97 } 98 99 time.Sleep(webhookCheckInterval) 100 101 require.Equal(t, int32(30), totalDropped.Load()+totalReceived.Load()) 102 // at least one request dropped 103 require.Less(t, int32(0), totalDropped.Load()) 104 } 105 106 func TestURLNotifierLifecycle(t *testing.T) { 107 s := newServer(testAddr) 108 require.NoError(t, s.Start()) 109 defer s.Stop() 110 111 t.Run("start/stop without use", func(t *testing.T) { 112 urlNotifier := newTestNotifier() 113 urlNotifier.Stop(false) 114 }) 115 116 t.Run("stop allowing to drain", 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(false) 127 require.Eventually(t, func() bool { return numCalled.Load() == 20 }, 5*time.Second, webhookCheckInterval) 128 }) 129 130 t.Run("force stop", func(t *testing.T) { 131 urlNotifier := newTestNotifier() 132 numCalled := atomic.Int32{} 133 s.handler = func(r *http.Request) { 134 numCalled.Inc() 135 } 136 for i := 0; i < 10; i++ { 137 _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomStarted}) 138 _ = urlNotifier.QueueNotify(&livekit.WebhookEvent{Event: EventRoomFinished}) 139 } 140 urlNotifier.Stop(true) 141 time.Sleep(time.Second) 142 require.Greater(t, int32(20), numCalled.Load()) 143 }) 144 } 145 146 func newTestNotifier() *URLNotifier { 147 return NewURLNotifier(URLNotifierParams{ 148 QueueSize: 20, 149 URL: testUrl, 150 APIKey: apiKey, 151 APISecret: apiSecret, 152 }) 153 } 154 155 type testServer struct { 156 handler func(r *http.Request) 157 server *http.Server 158 } 159 160 func newServer(addr string) *testServer { 161 s := &testServer{} 162 s.server = &http.Server{ 163 Addr: addr, 164 Handler: s, 165 } 166 return s 167 } 168 169 func (s *testServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 170 if s.handler != nil { 171 s.handler(r) 172 } 173 } 174 175 func (s *testServer) Start() error { 176 l, err := net.Listen("tcp", s.server.Addr) 177 if err != nil { 178 return err 179 } 180 go s.server.Serve(l) 181 return nil 182 } 183 184 func (s *testServer) Stop() { 185 _ = s.server.Shutdown(context.Background()) 186 }