194 lines
5.3 KiB
Go
194 lines
5.3 KiB
Go
package loadsim
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRunnerDialsTargetConnectionsAndWritesFrames(t *testing.T) {
|
|
var writes atomic.Int64
|
|
var closed atomic.Int64
|
|
runner := Runner{
|
|
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return &recordingConn{
|
|
write: func(p []byte) (int, error) {
|
|
writes.Add(1)
|
|
return len(p), nil
|
|
},
|
|
close: func() error {
|
|
closed.Add(1)
|
|
return nil
|
|
},
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
stats, err := runner.Run(context.Background(), Config{
|
|
Protocol: ProtocolJT808,
|
|
Addr: "127.0.0.1:808",
|
|
Connections: 3,
|
|
ConnectRatePerSecond: 1000,
|
|
SendInterval: time.Millisecond,
|
|
Duration: 5 * time.Millisecond,
|
|
Template: "0200",
|
|
SendFrames: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
|
|
if stats.ConnectionsOpened != 3 {
|
|
t.Fatalf("ConnectionsOpened = %d, want 3", stats.ConnectionsOpened)
|
|
}
|
|
if stats.FramesWritten == 0 {
|
|
t.Fatalf("FramesWritten = 0, want at least one")
|
|
}
|
|
if writes.Load() != int64(stats.FramesWritten) {
|
|
t.Fatalf("recorded writes = %d, stats = %d", writes.Load(), stats.FramesWritten)
|
|
}
|
|
if closed.Load() != 3 {
|
|
t.Fatalf("closed = %d, want 3", closed.Load())
|
|
}
|
|
}
|
|
|
|
func TestRunnerWritesVariantFrames(t *testing.T) {
|
|
writes := make(chan []byte, 8)
|
|
runner := Runner{
|
|
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return &recordingConn{
|
|
write: func(p []byte) (int, error) {
|
|
cp := append([]byte(nil), p...)
|
|
select {
|
|
case writes <- cp:
|
|
default:
|
|
}
|
|
return len(p), nil
|
|
},
|
|
close: func() error { return nil },
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
stats, err := runner.Run(context.Background(), Config{
|
|
Protocol: ProtocolJT808,
|
|
Addr: "127.0.0.1:808",
|
|
Connections: 1,
|
|
ConnectRatePerSecond: 1000,
|
|
SendInterval: time.Millisecond,
|
|
Duration: 6 * time.Millisecond,
|
|
Template: "0200",
|
|
SendFrames: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
if stats.FramesWritten < 2 {
|
|
t.Fatalf("FramesWritten = %d, want at least 2", stats.FramesWritten)
|
|
}
|
|
|
|
first := <-writes
|
|
second := <-writes
|
|
if string(first) == string(second) {
|
|
t.Fatal("runner wrote byte-identical frames; want per-frame variants")
|
|
}
|
|
}
|
|
|
|
func TestRunnerCanHoldConnectionsWithoutWritingFrames(t *testing.T) {
|
|
var writes atomic.Int64
|
|
runner := Runner{
|
|
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return &recordingConn{
|
|
write: func(p []byte) (int, error) {
|
|
writes.Add(1)
|
|
return len(p), nil
|
|
},
|
|
close: func() error { return nil },
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
stats, err := runner.Run(context.Background(), Config{
|
|
Protocol: ProtocolJT808,
|
|
Addr: "127.0.0.1:808",
|
|
Connections: 2,
|
|
ConnectRatePerSecond: 1000,
|
|
SendInterval: time.Millisecond,
|
|
Duration: 5 * time.Millisecond,
|
|
Template: "0200",
|
|
SendFrames: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
if stats.ConnectionsOpened != 2 {
|
|
t.Fatalf("ConnectionsOpened = %d, want 2", stats.ConnectionsOpened)
|
|
}
|
|
if stats.FramesWritten != 0 || writes.Load() != 0 {
|
|
t.Fatalf("frames written stats=%d writes=%d, want 0", stats.FramesWritten, writes.Load())
|
|
}
|
|
}
|
|
|
|
func TestRunnerDrainsProtocolResponses(t *testing.T) {
|
|
runner := Runner{
|
|
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
client, server := net.Pipe()
|
|
go func() {
|
|
defer server.Close()
|
|
buffer := make([]byte, 4096)
|
|
for {
|
|
if _, err := server.Read(buffer); err != nil {
|
|
return
|
|
}
|
|
if _, err := server.Write([]byte{0x7e, 0x80, 0x01, 0x7e}); err != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
return client, nil
|
|
},
|
|
}
|
|
|
|
stats, err := runner.Run(context.Background(), Config{
|
|
Protocol: ProtocolJT808,
|
|
Addr: "127.0.0.1:808",
|
|
Connections: 1,
|
|
ConnectRatePerSecond: 1000,
|
|
SendInterval: time.Millisecond,
|
|
Duration: 10 * time.Millisecond,
|
|
Template: "0200",
|
|
SendFrames: true,
|
|
DrainResponses: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Run() error = %v", err)
|
|
}
|
|
if stats.ResponseBytes == 0 {
|
|
t.Fatalf("ResponseBytes = 0, want drained protocol responses")
|
|
}
|
|
if stats.ReadErrors != 0 {
|
|
t.Fatalf("ReadErrors = %d, want 0", stats.ReadErrors)
|
|
}
|
|
}
|
|
|
|
type recordingConn struct {
|
|
write func([]byte) (int, error)
|
|
close func() error
|
|
}
|
|
|
|
func (c *recordingConn) Read(p []byte) (int, error) { return 0, context.Canceled }
|
|
func (c *recordingConn) Write(p []byte) (int, error) { return c.write(p) }
|
|
func (c *recordingConn) Close() error { return c.close() }
|
|
func (c *recordingConn) LocalAddr() net.Addr { return testAddr("local") }
|
|
func (c *recordingConn) RemoteAddr() net.Addr { return testAddr("remote") }
|
|
func (c *recordingConn) SetDeadline(t time.Time) error { return nil }
|
|
func (c *recordingConn) SetReadDeadline(t time.Time) error { return nil }
|
|
func (c *recordingConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
|
|
type testAddr string
|
|
|
|
func (a testAddr) Network() string { return "tcp" }
|
|
func (a testAddr) String() string { return string(a) }
|