gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/eventchannel/event_test.go (about) 1 // Copyright 2019 The gVisor Authors. 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 eventchannel 16 17 import ( 18 "fmt" 19 "testing" 20 "time" 21 22 "google.golang.org/protobuf/proto" 23 "gvisor.dev/gvisor/pkg/sync" 24 ) 25 26 // testEmitter is an emitter that can be used in tests. It records all events 27 // emitted, and whether it has been closed. 28 type testEmitter struct { 29 // mu protects all fields below. 30 mu sync.Mutex 31 32 // events contains all emitted events. 33 events []proto.Message 34 35 // closed records whether Close() was called. 36 closed bool 37 } 38 39 // Emit implements Emitter.Emit. 40 func (te *testEmitter) Emit(msg proto.Message) (bool, error) { 41 te.mu.Lock() 42 defer te.mu.Unlock() 43 te.events = append(te.events, msg) 44 return false, nil 45 } 46 47 // Close implements Emitter.Close. 48 func (te *testEmitter) Close() error { 49 te.mu.Lock() 50 defer te.mu.Unlock() 51 if te.closed { 52 return fmt.Errorf("closed called twice") 53 } 54 te.closed = true 55 return nil 56 } 57 58 // testMessage implements proto.Message for testing. 59 type testMessage struct { 60 proto.Message 61 62 // name is the name of the message, used by tests to compare messages. 63 name string 64 } 65 66 func TestMultiEmitter(t *testing.T) { 67 // Create three testEmitters, tied together in a multiEmitter. 68 me := &multiEmitter{} 69 var emitters []*testEmitter 70 for i := 0; i < 3; i++ { 71 te := &testEmitter{} 72 emitters = append(emitters, te) 73 me.AddEmitter(te) 74 } 75 76 // Emit three messages to multiEmitter. 77 names := []string{"foo", "bar", "baz"} 78 for _, name := range names { 79 m := testMessage{name: name} 80 if _, err := me.Emit(m); err != nil { 81 t.Fatalf("me.Emit(%v) failed: %v", m, err) 82 } 83 } 84 85 // All three emitters should have all three events. 86 for _, te := range emitters { 87 if got, want := len(te.events), len(names); got != want { 88 t.Fatalf("emitter got %d events, want %d", got, want) 89 } 90 for i, name := range names { 91 if got := te.events[i].(testMessage).name; got != name { 92 t.Errorf("emitter got message with name %q, want %q", got, name) 93 } 94 } 95 } 96 97 // Close multiEmitter. 98 if err := me.Close(); err != nil { 99 t.Fatalf("me.Close() failed: %v", err) 100 } 101 102 // All testEmitters should be closed. 103 for _, te := range emitters { 104 if !te.closed { 105 t.Errorf("te.closed got false, want true") 106 } 107 } 108 } 109 110 func TestRateLimitedEmitter(t *testing.T) { 111 // Create a RateLimittedEmitter that wraps a testEmitter. 112 te := &testEmitter{} 113 max := float64(5) // events per second 114 burst := 10 // events 115 rle := RateLimitedEmitterFrom(te, max, burst) 116 117 // Send 50 messages in one shot. 118 for i := 0; i < 50; i++ { 119 if _, err := rle.Emit(testMessage{}); err != nil { 120 t.Fatalf("rle.Emit failed: %v", err) 121 } 122 } 123 124 // We should have received only 10 messages. 125 if got, want := len(te.events), 10; got != want { 126 t.Errorf("got %d events, want %d", got, want) 127 } 128 129 // Sleep for a second and then send another 50. 130 time.Sleep(1 * time.Second) 131 for i := 0; i < 50; i++ { 132 if _, err := rle.Emit(testMessage{}); err != nil { 133 t.Fatalf("rle.Emit failed: %v", err) 134 } 135 } 136 137 // We should have at least 5 more message, plus maybe a few more if the 138 // test ran slowly. 139 got, wantAtLeast, wantAtMost := len(te.events), 15, 20 140 if got < wantAtLeast { 141 t.Errorf("got %d events, want at least %d", got, wantAtLeast) 142 } 143 if got > wantAtMost { 144 t.Errorf("got %d events, want at most %d", got, wantAtMost) 145 } 146 }