github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/client/channel/relentless_test.go (about) 1 // Copyright 2017 Google 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 // https://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 channel 16 17 import ( 18 "bytes" 19 "io" 20 "sort" 21 "testing" 22 23 log "github.com/golang/glog" 24 "google.golang.org/protobuf/proto" 25 26 "github.com/google/fleetspeak/fleetspeak/src/client/service" 27 28 fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak" 29 ) 30 31 func TestRelentlessLoop(t *testing.T) { 32 var mainEnd *Channel 33 34 r := make(chan struct{}, 1) 35 36 loopEnd := NewRelentlessChannel(func() (*Channel, func()) { 37 log.Info("building channel") 38 toLoopReader, toLoopWriter := io.Pipe() 39 fromLoopReader, fromLoopWriter := io.Pipe() 40 41 mainEnd = New(fromLoopReader, toLoopWriter) 42 43 r <- struct{}{} 44 45 return New(toLoopReader, fromLoopWriter), func() { 46 log.Info("shutting down channel") 47 toLoopReader.Close() 48 toLoopWriter.Close() 49 fromLoopReader.Close() 50 fromLoopWriter.Close() 51 } 52 }) 53 54 // closed to shutdown loopback 55 done := make(chan struct{}) 56 57 // channel of messages that the loopback has received an ack for. 58 acked := make(chan *fspb.Message, 20) 59 60 go func() { 61 defer func() { 62 log.Info("shutting down loopback") 63 close(loopEnd.Out) 64 }() 65 for { 66 select { 67 case m, ok := <-loopEnd.In: 68 if !ok { 69 t.Error("loopEnd.In was closed.") 70 return 71 } 72 loopEnd.Out <- service.AckMessage{M: m, Ack: func() { acked <- m }} 73 case <-done: 74 return 75 } 76 } 77 }() 78 79 // Wait for the first Builder call. 80 <-r 81 82 ra := NewRelentlessAcknowledger(mainEnd, 20) 83 84 msgs := []*fspb.Message{ 85 {SourceMessageId: []byte("A"), Source: &fspb.Address{ServiceName: "TestService"}}, 86 {SourceMessageId: []byte("B"), Source: &fspb.Address{ServiceName: "TestService"}}, 87 {SourceMessageId: []byte("C"), Source: &fspb.Address{ServiceName: "TestService"}}, 88 } 89 90 for _, m := range msgs { 91 mainEnd.Out <- m 92 } 93 94 // should not be acknowledged yet: 95 select { 96 case m := <-acked: 97 t.Errorf("Received unexpected ack: %v", m) 98 default: 99 } 100 101 // read them and ack them - read should be in order 102 for _, m := range msgs { 103 am, ok := <-ra.In 104 if !ok { 105 t.Fatal("ra.In unexpectedly closed") 106 } 107 if !proto.Equal(m, am.M) { 108 t.Errorf("Unexpected message read. got [%v], want [%v}", am.M, m) 109 } 110 am.Ack() 111 } 112 113 for i, m := range msgs { 114 got := <-acked 115 if !proto.Equal(m, got) { 116 t.Errorf("Unexpected ack in position %d, got [%v], want [%v]", i, got, m) 117 } 118 } 119 120 // Now we test the retry capability. Send 3 new messages. 121 msgs = []*fspb.Message{ 122 {SourceMessageId: []byte("D"), Source: &fspb.Address{ServiceName: "TestService"}}, 123 {SourceMessageId: []byte("E"), Source: &fspb.Address{ServiceName: "TestService"}}, 124 {SourceMessageId: []byte("F"), Source: &fspb.Address{ServiceName: "TestService"}}, 125 } 126 127 for _, m := range msgs { 128 mainEnd.Out <- m 129 } 130 131 // read them but do not ack them - read should be in order 132 for _, m := range msgs { 133 am, ok := <-ra.In 134 if !ok { 135 t.Fatal("out unexpectedly closed") 136 } 137 if !proto.Equal(m, am.M) { 138 t.Errorf("Unexpected message read. got [%v], want [%v}", am.M, m) 139 } 140 } 141 142 // close mainEnd 143 ra.Stop() 144 close(mainEnd.Out) 145 146 // wait for it to be rebuilt 147 <-r 148 149 // start a new Acknowledger 150 ra = NewRelentlessAcknowledger(mainEnd, 20) 151 152 // Should be able to read and ack the messages. Retry order may be different, 153 // so we collect and sort. 154 var got []*fspb.Message 155 for range msgs { 156 am, ok := <-ra.In 157 if !ok { 158 t.Fatal("ra.In unexpectedly closed") 159 } 160 am.Ack() 161 got = append(got, am.M) 162 } 163 164 sort.Slice(got, func(i, j int) bool { 165 return bytes.Compare(got[i].SourceMessageId, got[j].SourceMessageId) == -1 166 }) 167 168 for i, m := range msgs { 169 if !proto.Equal(m, got[i]) { 170 t.Errorf("Unexpected message read. got [%v], want [%v}", got[i], m) 171 } 172 } 173 174 ra.Stop() 175 close(mainEnd.Out) 176 close(done) 177 }