github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/systests/sys_test.go (about) 1 /* 2 Copyright 2016 Stanislav Liberman 3 Copyright 2022 Steven Stern 4 5 Licensed under the Apache License, Version 2.0 (the "License"); 6 you may not use this file except in compliance with the License. 7 You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 */ 17 18 package systests 19 20 import ( 21 "flag" 22 "fmt" 23 "github.com/lirm/aeron-go/systests/driver" 24 "github.com/stretchr/testify/suite" 25 "testing" 26 "time" 27 28 "github.com/lirm/aeron-go/aeron" 29 "github.com/lirm/aeron-go/aeron/atomic" 30 "github.com/lirm/aeron-go/aeron/logbuffer" 31 "github.com/lirm/aeron-go/aeron/logging" 32 ) 33 34 var ExamplesConfig = struct { 35 TestChannel *string 36 TestStreamID *int 37 LoggingOn *bool 38 }{ 39 flag.String("c", "aeron:ipc", "test channel"), 40 flag.Int("s", 10, "streamId to use"), 41 flag.Bool("l", false, "enable logging"), 42 } 43 44 var logger = logging.MustGetLogger("systests") 45 46 type SysTestSuite struct { 47 suite.Suite 48 mediaDriver *driver.MediaDriver 49 } 50 51 func (suite *SysTestSuite) SetupTest() { 52 mediaDriver, err := driver.StartMediaDriver() 53 suite.Require().NoError(err, "Couldn't start Media Driver: ") 54 suite.mediaDriver = mediaDriver 55 } 56 57 func (suite *SysTestSuite) TearDownTest() { 58 suite.mediaDriver.StopMediaDriver() 59 } 60 61 func (suite *SysTestSuite) send(n int, pub *aeron.Publication) { 62 message := "this is a message" 63 srcBuffer := atomic.MakeBuffer(([]byte)(message)) 64 65 for i := 0; i < n; i++ { 66 timeoutAt := time.Now().Add(time.Second * 5) 67 var v int64 68 for v <= 0 { 69 v = pub.Offer(srcBuffer, 0, int32(len(message)), nil) 70 if time.Now().After(timeoutAt) { 71 suite.Fail("Send timed out") 72 } 73 time.Sleep(time.Millisecond) 74 } 75 } 76 } 77 78 func (suite *SysTestSuite) receive(n int, sub *aeron.Subscription) { 79 counter := 0 80 handler := func(buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) { 81 logger.Debugf(" message: %s", string(buffer.GetBytesArray(offset, length))) 82 counter++ 83 } 84 var fragmentsRead atomic.Int 85 for int(fragmentsRead.Get()) < n { 86 timeoutAt := time.Now().Add(time.Second) 87 for { 88 recvd := sub.Poll(handler, 10) 89 if recvd >= 1 { 90 fragmentsRead.Add(int32(recvd)) 91 logger.Debugf(" have %d fragments", fragmentsRead) 92 break 93 } 94 if time.Now().After(timeoutAt) { 95 suite.Fail("Receive timed out") 96 } 97 time.Sleep(time.Millisecond) 98 } 99 } 100 suite.Assert().EqualValues(fragmentsRead.Get(), n) 101 suite.Assert().EqualValues(counter, n) 102 } 103 104 func (suite *SysTestSuite) subAndSend(n int, a *aeron.Aeron, pub *aeron.Publication) { 105 sub, err := a.AddSubscription(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 106 suite.Require().NoError(err) 107 defer sub.Close() 108 109 // This is basically a requirement since we need to wait 110 for !aeron.IsConnectedTo(sub, pub) { 111 time.Sleep(time.Millisecond) 112 } 113 114 suite.send(n, pub) 115 suite.receive(n, sub) 116 } 117 118 func logtest(flag bool) { 119 fmt.Printf("Logging: %t\n", flag) 120 if flag { 121 logging.SetLevel(logging.DEBUG, "aeron") 122 logging.SetLevel(logging.DEBUG, "memmap") 123 logging.SetLevel(logging.DEBUG, "driver") 124 logging.SetLevel(logging.DEBUG, "counters") 125 logging.SetLevel(logging.DEBUG, "logbuffers") 126 logging.SetLevel(logging.DEBUG, "buffer") 127 } else { 128 logging.SetLevel(logging.INFO, "aeron") 129 logging.SetLevel(logging.INFO, "memmap") 130 logging.SetLevel(logging.INFO, "driver") 131 logging.SetLevel(logging.INFO, "counters") 132 logging.SetLevel(logging.INFO, "logbuffers") 133 logging.SetLevel(logging.INFO, "buffer") 134 135 } 136 } 137 138 // TestAeronBasics will check for a simple send/receive scenario. 139 func (suite *SysTestSuite) TestAeronBasics() { 140 logger.Debug("Started TestAeronBasics") 141 142 a, err := aeron.Connect(aeron.NewContext().AeronDir(suite.mediaDriver.TempDir)) 143 if err != nil { 144 suite.Failf("Failed to connect to driver: %s", err.Error()) 145 } 146 defer a.Close() 147 148 pub, err := a.AddPublication(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 149 suite.Require().NoError(err) 150 defer pub.Close() 151 //logger.Debugf("Added publication: %v\n", pub) 152 153 suite.subAndSend(1, a, pub) 154 } 155 156 // TestAeronSendMultipleMessages tests sending and receive multiple messages in a row. 157 func (suite *SysTestSuite) TestAeronSendMultipleMessages() { 158 logger.Debug("Started TestAeronSendMultipleMessages") 159 160 a, err := aeron.Connect(aeron.NewContext().AeronDir(suite.mediaDriver.TempDir)) 161 suite.Require().Nil(err, "Failed to connect to driver: %s", err) 162 defer a.Close() 163 164 for i := 0; i < 3; i++ { 165 logger.Debugf("NextCorrelationID = %d", a.NextCorrelationID()) 166 } 167 suite.Require().NotEqual(a.NextCorrelationID(), 0, "invalid zero NextCorrelationID") 168 169 pub, err := a.AddPublication(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 170 suite.Require().NoError(err) 171 defer pub.Close() 172 173 sub, err := a.AddSubscription(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 174 suite.Require().NoError(err) 175 defer sub.Close() 176 177 // This is basically a requirement since we need to wait 178 for !aeron.IsConnectedTo(sub, pub) { 179 time.Sleep(time.Millisecond) 180 } 181 182 itCount := 100 183 go suite.send(itCount, pub) 184 suite.receive(itCount, sub) 185 } 186 187 // TestAeronSendMultiplePublications tests sending on multiple publications with a sigle 188 // subscription receiving. In IPC local mode this will end up with using the same Publication 189 // but it's a scenario nonetheless. As all systests this assumes a running media driver. 190 func (suite *SysTestSuite) NotTestedYet_TestAeronSendMultiplePublications() { 191 logger.Debug("Started TestAeronSendMultiplePublications") 192 193 //go func() { 194 // sigs := make(chan os.Signal, 1) 195 // signal.Notify(sigs, syscall.SIGQUIT) 196 // buf := make([]byte, 1<<20) 197 // for { 198 // <-sigs 199 // stacklen := runtime.Stack(buf, true) 200 // log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen]) 201 // } 202 //}() 203 204 a, err := aeron.Connect(aeron.NewContext()) 205 if err != nil { 206 logger.Fatalf("Failed to connect to driver: %s\n", err.Error()) 207 } 208 defer a.Close() 209 210 pubCount := 10 211 itCount := 100 212 213 sub, err := a.AddSubscription(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 214 suite.Require().NoError(err) 215 defer sub.Close() 216 217 pubs := make([]*aeron.Publication, pubCount) 218 219 for i := 0; i < pubCount; i++ { 220 pub, err := a.AddPublication(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 221 suite.Require().NoError(err) 222 defer pub.Close() 223 224 pubs[i] = pub 225 226 // This is basically a requirement since we need to wait 227 for !aeron.IsConnectedTo(sub, pub) { 228 time.Sleep(time.Millisecond) 229 } 230 } 231 232 logger.Debugf(" ==> Got pubs %v", pubs) 233 234 go suite.receive(itCount*pubCount, sub) 235 236 time.Sleep(200 * time.Millisecond) 237 238 // Send 239 for i := 0; i < itCount; i++ { 240 for pIx, p := range pubs { 241 suite.send(1, p) 242 logger.Debugf("sent %d to pubs[%d]", i, pIx) 243 logger.Debugf("sent %d to pubs[%d]", i, pIx) 244 } 245 } 246 247 } 248 249 // TestAeronResubscribe test using different subscriptions with the same publication 250 func (suite *SysTestSuite) NotTestedYet_TestAeronResubscribe() { 251 logger.Debug("Started TestAeronResubscribe") 252 253 a, err := aeron.Connect(aeron.NewContext()) 254 suite.Require().NoError(err) 255 defer a.Close() 256 257 pub, err := a.AddPublication(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 258 suite.Require().NoError(err) 259 260 suite.subAndSend(1, a, pub) 261 suite.subAndSend(1, a, pub) 262 } 263 264 // TestResubStress tests sending and receiving when creating a new subscription for each cycle 265 func (suite *SysTestSuite) NotTestedYet_TestResubStress() { 266 logger.Debug("Started TestAeronResubscribe") 267 268 a, err := aeron.Connect(aeron.NewContext()) 269 suite.Require().NoError(err) 270 defer a.Close() 271 272 pub, err := a.AddPublication(*ExamplesConfig.TestChannel, int32(*ExamplesConfig.TestStreamID)) 273 suite.Require().NoError(err) 274 for i := 0; i < 100; i++ { 275 suite.subAndSend(1, a, pub) 276 logger.Debugf("bounce %d", i) 277 } 278 } 279 280 // TestAeronClose simply tests explicit call to ctx.Close() 281 func testAeronClose() { 282 logger.Debug("Started TestAeronClose") 283 284 ctx := aeron.NewContext().MediaDriverTimeout(time.Second * 5) 285 a, err := aeron.Connect(ctx) 286 if err != nil { 287 logger.Fatalf("Failed to connect to driver: %s\n", err.Error()) 288 } 289 a.Close() 290 } 291 292 func TestSuiteMain(t *testing.T) { 293 flag.Parse() 294 logtest(*ExamplesConfig.LoggingOn) 295 suite.Run(t, new(SysTestSuite)) 296 297 //testAeronClose() 298 299 //testAeronResubscribe() 300 301 //testAeronSendMultiplePublications() 302 303 //testResubStress() 304 }