fix: golangci errors

This commit is contained in:
zarazaex69
2026-05-11 02:21:41 +03:00
parent 7be008b99e
commit 0723ddf2f5
50 changed files with 397 additions and 278 deletions

View File

@@ -25,9 +25,9 @@ const modeGen = "gen"
// ErrDataDirRequired is returned when no data directory is specified.
var ErrDataDirRequired = errors.New("data directory required (use -data data)")
var runSession = session.Run
var runSession = session.Run //nolint:gochecknoglobals // package-level state intentional
var runGen = execGen
var runGen = execGen //nolint:gochecknoglobals // package-level state intentional
type config struct {
mode string

View File

@@ -12,18 +12,21 @@ import (
"github.com/openlibrecommunity/olcrtc/internal/logger"
)
var errBoom = errors.New("boom")
//nolint:cyclop // table-driven test naturally has many branches
func TestToSessionConfig(t *testing.T) {
cfg := config{
mode: "cnc",
link: "direct",
link: "direct", //nolint:goconst // test literal, repetition is intentional
transport: "vp8channel",
carrier: "jazz",
roomID: "room",
clientID: "client",
keyHex: "key",
carrier: "jazz", //nolint:goconst // test literal, repetition is intentional
roomID: "room", //nolint:goconst // test literal, repetition is intentional
clientID: "client", //nolint:goconst // test literal, repetition is intentional
keyHex: "key", //nolint:goconst // test literal, repetition is intentional
socksHost: "127.0.0.1",
socksPort: 1080,
dnsServer: "1.1.1.1:53",
dnsServer: "1.1.1.1:53", //nolint:goconst // test literal, repetition is intentional
socksProxyAddr: "proxy",
socksProxyPort: 1081,
videoWidth: 640,
@@ -55,9 +58,10 @@ func TestToSessionConfig(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestParseFlagsFrom(t *testing.T) {
cfg, err := parseFlagsFrom([]string{
"-mode", "srv",
"-mode", "srv", //nolint:goconst // test literal, repetition is intentional
"-link", "direct",
"-transport", "vp8channel",
"-carrier", "telemost",
@@ -109,11 +113,11 @@ func TestParseFlagsFrom(t *testing.T) {
func TestRunGenModeValidationErrors(t *testing.T) {
session.RegisterDefaults()
if err := runWithConfig(config{mode: "gen"}); err == nil {
if err := runWithConfig(config{mode: "gen"}); err == nil { //nolint:goconst // test literal, repetition is intentional
t.Fatal("runWithConfig(gen, no carrier) error = nil")
}
if err := runWithConfig(config{mode: "gen", carrier: "wbstream", dnsServer: "1.1.1.1:53"}); err == nil {
if err := runWithConfig(config{mode: "gen", carrier: "wbstream", dnsServer: "1.1.1.1:53"}); err == nil { //nolint:goconst,lll // test literal, repetition is intentional
t.Fatal("runWithConfig(gen, amount=0) error = nil")
}
}
@@ -268,7 +272,7 @@ func TestWaitForShutdown(t *testing.T) {
t.Fatalf("waitForShutdown(nil) error = %v", err)
}
want := errors.New("boom")
want := errBoom
errCh = make(chan error, 1)
errCh <- want
if err := waitForShutdown(errCh); !errors.Is(err, want) {

View File

@@ -6,6 +6,7 @@ import (
"testing"
)
//nolint:maintidx // table-driven validation test naturally has many cases
func TestValidate(t *testing.T) {
RegisterDefaults()
@@ -13,11 +14,11 @@ func TestValidate(t *testing.T) {
Mode: modeSRV,
Link: "direct",
Transport: "datachannel",
Carrier: "telemost",
Carrier: "telemost", //nolint:goconst // test literal, repetition is intentional
RoomID: "room-1",
ClientID: "client-1",
KeyHex: "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
DNSServer: "1.1.1.1:53",
DNSServer: "1.1.1.1:53", //nolint:goconst // test literal, repetition is intentional
}
tests := []struct {
@@ -30,7 +31,7 @@ func TestValidate(t *testing.T) {
name: "jazz allows empty room id",
cfg: func() Config {
cfg := base
cfg.Carrier = "jazz"
cfg.Carrier = "jazz" //nolint:goconst // test literal, repetition is intentional
cfg.RoomID = ""
return cfg
}(),
@@ -58,7 +59,7 @@ func TestValidate(t *testing.T) {
name: "unsupported carrier",
cfg: func() Config {
cfg := base
cfg.Carrier = "unknown"
cfg.Carrier = "unknown" //nolint:goconst // test literal, repetition is intentional
return cfg
}(),
want: ErrUnsupportedCarrier,
@@ -121,7 +122,7 @@ func TestValidate(t *testing.T) {
name: "videochannel requires dimensions and bitrate settings",
cfg: func() Config {
cfg := base
cfg.Transport = "videochannel"
cfg.Transport = "videochannel" //nolint:goconst // test literal, repetition is intentional
return cfg
}(),
want: ErrVideoWidthRequired,
@@ -135,7 +136,7 @@ func TestValidate(t *testing.T) {
cfg.VideoHeight = 480
cfg.VideoFPS = 30
cfg.VideoBitrate = "1M"
cfg.VideoHW = "none"
cfg.VideoHW = "none" //nolint:goconst // test literal, repetition is intentional
cfg.VideoCodec = "bogus"
return cfg
}(),
@@ -220,7 +221,7 @@ func TestValidate(t *testing.T) {
name: "vp8channel requires fps",
cfg: func() Config {
cfg := base
cfg.Transport = "vp8channel"
cfg.Transport = "vp8channel" //nolint:goconst // test literal, repetition is intentional
return cfg
}(),
want: ErrVP8FPSRequired,
@@ -249,7 +250,7 @@ func TestValidate(t *testing.T) {
name: "seichannel requires fps",
cfg: func() Config {
cfg := base
cfg.Transport = "seichannel"
cfg.Transport = "seichannel" //nolint:goconst // test literal, repetition is intentional
return cfg
}(),
want: ErrSEIFPSRequired,
@@ -346,7 +347,7 @@ func TestBuildRoomURL(t *testing.T) {
{carrier: "telemost", roomID: "abc", want: "https://telemost.yandex.ru/j/abc"},
{carrier: "jazz", roomID: "", want: "any"},
{carrier: "jazz", roomID: "room", want: "room"},
{carrier: "wbstream", roomID: "wb", want: "wb"},
{carrier: "wbstream", roomID: "wb", want: "wb"}, //nolint:goconst // test literal, repetition is intentional
{carrier: "other", roomID: "raw", want: "raw"},
}

View File

@@ -9,6 +9,13 @@ import (
"github.com/pion/webrtc/v4"
)
var (
errConnectBoom = errors.New("connect boom")
errSendBoom = errors.New("send boom")
errCloseBoom = errors.New("close boom")
errTrackBoom = errors.New("track boom")
)
type stubProvider struct {
connectErr error
sendErr error
@@ -114,9 +121,9 @@ func TestProviderByteStreamWrapsProviderAndCallbacks(t *testing.T) {
func TestProviderByteStreamWrapsErrors(t *testing.T) {
prov := &stubProvider{
connectErr: errors.New("connect boom"),
sendErr: errors.New("send boom"),
closeErr: errors.New("close boom"),
connectErr: errConnectBoom,
sendErr: errSendBoom,
closeErr: errCloseBoom,
}
stream := &providerByteStream{provider: prov}
@@ -162,7 +169,7 @@ func TestProviderSessionOpenByteStreamAndVideoTrack(t *testing.T) {
}
func TestProviderVideoTrackWrapsOperations(t *testing.T) {
prov := &stubProvider{canSend: true, addTrackErr: errors.New("track boom")}
prov := &stubProvider{canSend: true, addTrackErr: errTrackBoom}
track := &providerVideoTrack{provider: prov}
called := false
@@ -184,8 +191,8 @@ func TestProviderVideoTrackWrapsOperations(t *testing.T) {
func TestProviderVideoTrackWrapsConnectCloseErrors(t *testing.T) {
prov := &stubProvider{
connectErr: errors.New("connect boom"),
closeErr: errors.New("close boom"),
connectErr: errConnectBoom,
closeErr: errCloseBoom,
}
track := &providerVideoTrack{provider: prov}

View File

@@ -49,7 +49,7 @@ type Config struct {
// Factory creates a new carrier session.
type Factory func(ctx context.Context, cfg Config) (Session, error)
var registry = make(map[string]Factory)
var registry = make(map[string]Factory) //nolint:gochecknoglobals // package-level state intentional
// Register adds a carrier factory to the registry.
func Register(name string, factory Factory) {

View File

@@ -16,6 +16,8 @@ import (
"github.com/xtaci/smux"
)
var errUnexpectedConnectRequest = errors.New("unexpected connect request")
func TestSetupCipher(t *testing.T) {
keyHex := "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
cipher, err := setupCipher(keyHex)
@@ -98,7 +100,8 @@ func TestSocks5HandshakeWithAuth(t *testing.T) {
t.Fatalf("method selection = %v, want [5 2]", resp)
}
// Send the auth sub-negotiation: VER(1) + ULEN(1) + USER + PLEN(1) + PASS
authReq := []byte{0x01, 0x04}
authReq := make([]byte, 0, 11)
authReq = append(authReq, 0x01, 0x04)
authReq = append(authReq, []byte("user")...)
authReq = append(authReq, 0x04)
authReq = append(authReq, []byte("pass")...)
@@ -141,7 +144,8 @@ func TestSocks5HandshakeAuthRejected(t *testing.T) {
t.Fatalf("ReadFull method: %v", err)
}
// Send wrong credentials
authReq := []byte{0x01, 0x04}
authReq := make([]byte, 0, 12)
authReq = append(authReq, 0x01, 0x04)
authReq = append(authReq, []byte("user")...)
authReq = append(authReq, 0x05)
authReq = append(authReq, []byte("wrong")...)
@@ -266,7 +270,8 @@ func TestSocks5RequestDomain(t *testing.T) {
}{addr: addr, port: port, err: err}
}()
req := []byte{5, 1, 0, 3, 11}
req := make([]byte, 0, 16)
req = append(req, 5, 1, 0, 3, 11)
req = append(req, []byte("example.com")...)
port := make([]byte, 2)
binary.BigEndian.PutUint16(port, 443)
@@ -379,6 +384,7 @@ func TestReadSocks5AddrReadErrors(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestSendConnectRequestOverSmux(t *testing.T) {
a, b := net.Pipe()
defer func() {
@@ -411,8 +417,8 @@ func TestSendConnectRequestOverSmux(t *testing.T) {
done <- err
return
}
if req["cmd"] != "connect" || req["clientId"] != "client-1" || req["addr"] != "example.com" {
done <- errors.New("unexpected connect request")
if req["cmd"] != "connect" || req["clientId"] != "client-1" || req["addr"] != "example.com" { //nolint:goconst,lll // test literal, repetition is intentional
done <- errUnexpectedConnectRequest
return
}
_, err = stream.Write([]byte{0x00})
@@ -486,7 +492,7 @@ func (s *closerLinkStub) SetEndedCallback(func(string)) {}
func (s *closerLinkStub) WatchConnection(context.Context) {}
func (s *closerLinkStub) CanSend() bool { return true }
func TestOnDataWithNilConn(t *testing.T) {
func TestOnDataWithNilConn(_ *testing.T) {
c := &Client{}
c.onData([]byte("ignored"))
}

View File

@@ -29,37 +29,46 @@ import (
const testKeyHex = "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
var (
realE2E = flag.Bool(
errRealE2ENotReady = errors.New("real e2e client did not become ready")
errTunnelDidNotStop = errors.New("tunnel goroutine did not stop")
errRealE2EEchoMismatch = errors.New("real e2e echo payload mismatch")
errSocksUnexpectedReply = errors.New("unexpected SOCKS5 reply")
errSocksUnexpectedHello = errors.New("unexpected SOCKS5 greeting")
errPayloadMismatchOffset = errors.New("payload mismatch at offset")
)
var (
realE2E = flag.Bool( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-e2e",
false,
"run real provider e2e matrix against external WebRTC services",
)
realE2ECarriers = flag.String(
realE2ECarriers = flag.String( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-carriers",
"telemost,wbstream",
"comma-separated carriers for real e2e",
)
realE2ETransports = flag.String(
realE2ETransports = flag.String( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-transports",
"datachannel,videochannel,seichannel,vp8channel",
"comma-separated transports for real e2e",
)
realE2EJazzRoom = flag.String(
realE2EJazzRoom = flag.String( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-jazz-room",
"",
"SaluteJazz room for real e2e, format roomID:password; autogenerated when empty",
)
realE2ETelemostRoom = flag.String(
realE2ETelemostRoom = flag.String( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-telemost-room",
"41514917109506",
"Telemost room URL or id for real e2e",
)
realE2EWBStreamRoom = flag.String(
realE2EWBStreamRoom = flag.String( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-wbstream-room",
"",
"WB Stream room id for real e2e; autogenerated when empty",
)
realE2ETimeout = flag.Duration(
realE2ETimeout = flag.Duration( //nolint:gochecknoglobals // package-level state intentional
"olcrtc.real-timeout",
90*time.Second,
"timeout per real e2e provider/transport case",
@@ -288,7 +297,7 @@ func registerMemoryCarrier(t *testing.T) (string, *memoryRoom) {
return name, room
}
func registerMemoryCarrierAs(t *testing.T, name string) *memoryRoom {
func registerMemoryCarrierAs(t *testing.T, name string) {
t.Helper()
room := &memoryRoom{streams: make(map[*memoryStream]struct{})}
@@ -299,11 +308,10 @@ func registerMemoryCarrierAs(t *testing.T, name string) *memoryRoom {
room.mu.Unlock()
return &memorySession{stream: stream}, nil
})
return room
}
func builtInCarrierNames() []string {
return []string{"jazz", "telemost", "wbstream"}
return []string{"jazz", "telemost", "wbstream"} //nolint:goconst // test literal, repetition is intentional
}
func builtInTransportNames() []string {
@@ -340,6 +348,7 @@ func splitTestList(value string) []string {
return items
}
//nolint:cyclop // table-driven test naturally has many branches
func realRoomURL(ctx context.Context, t *testing.T, carrierName string) string {
t.Helper()
@@ -441,7 +450,8 @@ func validLinkConfig(carrierName, transportName string) link.Config {
func startEchoServer(t *testing.T) string {
t.Helper()
ln, err := net.Listen("tcp4", "127.0.0.1:0")
var lc net.ListenConfig
ln, err := lc.Listen(context.Background(), "tcp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen echo: %v", err)
}
@@ -463,9 +473,10 @@ func startEchoServer(t *testing.T) string {
return ln.Addr().String()
}
func freeLocalAddr(t *testing.T) string {
func freeLocalAddr(ctx context.Context, t *testing.T) string {
t.Helper()
ln, err := net.Listen("tcp4", "127.0.0.1:0")
var lc net.ListenConfig
ln, err := lc.Listen(ctx, "tcp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("reserve local addr: %v", err)
}
@@ -497,10 +508,9 @@ func startTunnel(t *testing.T, serverClientID, clientClientID string) *tunnelRun
t.Helper()
carrierName, room := registerMemoryCarrier(t)
socksAddr := freeLocalAddr(t)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
socksAddr := freeLocalAddr(ctx, t)
serverErr := make(chan error, 1)
go func() {
@@ -581,14 +591,14 @@ func startTunnel(t *testing.T, serverClientID, clientClientID string) *tunnelRun
}
func startRealTunnel(
t *testing.T,
ctx context.Context,
t *testing.T,
carrierName, transportName, roomURL, serverClientID, clientClientID string,
) (*tunnelRuntime, error) {
t.Helper()
session.RegisterDefaults()
socksAddr := freeLocalAddr(t)
socksAddr := freeLocalAddr(ctx, t)
runCtx, cancel := context.WithCancel(ctx)
t.Cleanup(cancel)
@@ -680,7 +690,7 @@ func startRealTunnel(
return nil, fmt.Errorf("server exited before client ready: %w", err)
case <-time.After(*realE2ETimeout):
cancel()
return nil, errors.New("real e2e client did not become ready")
return nil, errRealE2ENotReady
case <-runCtx.Done():
cancel()
return nil, fmt.Errorf("real e2e context ended before ready: %w", runCtx.Err())
@@ -721,7 +731,7 @@ func (r *tunnelRuntime) waitStoppedErr() error {
return fmt.Errorf("%s returned error: %w", name, err)
}
case <-time.After(3 * time.Second):
return fmt.Errorf("%s did not stop", name)
return fmt.Errorf("%w: %s", errTunnelDidNotStop, name)
}
}
return nil
@@ -730,7 +740,8 @@ func (r *tunnelRuntime) waitStoppedErr() error {
func connectViaSOCKS(t *testing.T, socksAddr, targetAddr string) net.Conn {
t.Helper()
conn, err := net.DialTimeout("tcp4", socksAddr, 2*time.Second)
dialer := net.Dialer{Timeout: 2 * time.Second}
conn, err := dialer.DialContext(context.Background(), "tcp4", socksAddr)
if err != nil {
t.Fatalf("dial socks: %v", err)
}
@@ -759,10 +770,11 @@ func connectViaSOCKS(t *testing.T, socksAddr, targetAddr string) net.Conn {
_ = conn.Close()
t.Fatalf("parse target port: %v", err)
}
req := []byte{5, 1, 0, 1}
req := make([]byte, 0, 10)
req = append(req, 5, 1, 0, 1)
req = append(req, net.ParseIP(host).To4()...)
var portBuf [2]byte
binary.BigEndian.PutUint16(portBuf[:], uint16(port))
binary.BigEndian.PutUint16(portBuf[:], uint16(port)) //nolint:gosec // SOCKS5 port is uint16 by definition
req = append(req, portBuf[:]...)
if _, err := conn.Write(req); err != nil {
_ = conn.Close()
@@ -785,7 +797,8 @@ func connectViaSOCKS(t *testing.T, socksAddr, targetAddr string) net.Conn {
func connectViaSOCKSExpectFailure(t *testing.T, socksAddr, targetAddr string) []byte {
t.Helper()
conn, err := net.DialTimeout("tcp4", socksAddr, 2*time.Second)
dialer := net.Dialer{Timeout: 2 * time.Second}
conn, err := dialer.DialContext(context.Background(), "tcp4", socksAddr)
if err != nil {
t.Fatalf("dial socks: %v", err)
}
@@ -807,10 +820,11 @@ func connectViaSOCKSExpectFailure(t *testing.T, socksAddr, targetAddr string) []
if err != nil {
t.Fatalf("parse target port: %v", err)
}
req := []byte{5, 1, 0, 1}
req := make([]byte, 0, 10)
req = append(req, 5, 1, 0, 1)
req = append(req, net.ParseIP(host).To4()...)
var portBuf [2]byte
binary.BigEndian.PutUint16(portBuf[:], uint16(port))
binary.BigEndian.PutUint16(portBuf[:], uint16(port)) //nolint:gosec // SOCKS5 port is uint16 by definition
req = append(req, portBuf[:]...)
if _, err := conn.Write(req); err != nil {
t.Fatalf("write socks connect: %v", err)
@@ -898,6 +912,7 @@ func TestDirectLinkConnectsFastProviderTransportMatrix(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestRealProviderTransportMatrix(t *testing.T) {
if !*realE2E {
t.Skip("real provider e2e disabled; pass -olcrtc.real-e2e with provider room flags")
@@ -944,7 +959,7 @@ func runRealE2ECase(t *testing.T, carrierName, transportName, roomURL, echoAddr
ctx, cancel := context.WithTimeout(context.Background(), *realE2ETimeout)
defer cancel()
rt, err := startRealTunnel(t, ctx, carrierName, transportName, roomURL, "client-1", "client-1")
rt, err := startRealTunnel(ctx, t, carrierName, transportName, roomURL, "client-1", "client-1")
if err != nil {
return err
}
@@ -972,7 +987,7 @@ func runRealE2ECase(t *testing.T, carrierName, transportName, roomURL, echoAddr
return fmt.Errorf("read real e2e echo: %w", err)
}
if !bytes.Equal(line, payload) {
return fmt.Errorf("real e2e echo = %q, want %q", line, payload)
return fmt.Errorf("%w: got %q, want %q", errRealE2EEchoMismatch, line, payload)
}
return nil
}
@@ -1082,51 +1097,53 @@ func connectViaSOCKSWithin(socksAddr, targetAddr string, timeout time.Duration)
}
func tryConnectViaSOCKS(socksAddr, targetAddr string) (net.Conn, error) {
conn, err := net.DialTimeout("tcp4", socksAddr, 500*time.Millisecond)
dialer := net.Dialer{Timeout: 500 * time.Millisecond}
conn, err := dialer.DialContext(context.Background(), "tcp4", socksAddr)
if err != nil {
return nil, err
return nil, fmt.Errorf("dial socks: %w", err)
}
if _, err := conn.Write([]byte{5, 1, 0}); err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("write greeting: %w", err)
}
greeting := make([]byte, 2)
if _, err := io.ReadFull(conn, greeting); err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("read greeting: %w", err)
}
if !bytes.Equal(greeting, []byte{5, 0}) {
_ = conn.Close()
return nil, fmt.Errorf("unexpected greeting: %v", greeting)
return nil, fmt.Errorf("%w: %v", errSocksUnexpectedHello, greeting)
}
host, portText, err := net.SplitHostPort(targetAddr)
if err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("split host port: %w", err)
}
port, err := strconv.Atoi(portText)
if err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("parse port: %w", err)
}
req := []byte{5, 1, 0, 1}
req := make([]byte, 0, 10)
req = append(req, 5, 1, 0, 1)
req = append(req, net.ParseIP(host).To4()...)
var portBuf [2]byte
binary.BigEndian.PutUint16(portBuf[:], uint16(port))
binary.BigEndian.PutUint16(portBuf[:], uint16(port)) //nolint:gosec // SOCKS5 port is uint16 by definition
req = append(req, portBuf[:]...)
if _, err := conn.Write(req); err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("write connect request: %w", err)
}
reply := make([]byte, 10)
if _, err := io.ReadFull(conn, reply); err != nil {
_ = conn.Close()
return nil, err
return nil, fmt.Errorf("read connect reply: %w", err)
}
if !bytes.Equal(reply, []byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) {
_ = conn.Close()
return nil, fmt.Errorf("unexpected reply: %v", reply)
return nil, fmt.Errorf("%w: %v", errSocksUnexpectedReply, reply)
}
return conn, nil
}
@@ -1175,14 +1192,14 @@ func streamPatternAndVerifyEcho(conn net.Conn, size int64) error {
n = int(remaining)
}
if err := conn.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
return err
return fmt.Errorf("set read deadline: %w", err)
}
if _, err := io.ReadFull(conn, buf[:n]); err != nil {
return fmt.Errorf("read at %d: %w", read, err)
}
fillPattern(want[:n], read)
if !bytes.Equal(buf[:n], want[:n]) {
return fmt.Errorf("payload mismatch at offset %d", read)
return fmt.Errorf("%w %d", errPayloadMismatchOffset, read)
}
read += int64(n)
}

View File

@@ -9,6 +9,13 @@ import (
"github.com/openlibrecommunity/olcrtc/internal/transport"
)
var (
errDirectBoom = errors.New("boom")
errDirectConnectBoom = errors.New("connect boom")
errDirectSendBoom = errors.New("send boom")
errDirectCloseBoom = errors.New("close boom")
)
type stubTransport struct {
connectErr error
sendErr error
@@ -41,6 +48,7 @@ func (s *stubTransport) WatchConnection(context.Context) { s.watched = true }
func (s *stubTransport) CanSend() bool { return s.canSend }
func (s *stubTransport) Features() transport.Features { return transport.Features{} }
//nolint:cyclop // table-driven test naturally has many branches
func TestNewForwardsConfigAndMethods(t *testing.T) {
name := "direct-test-forward"
var seen transport.Config
@@ -109,7 +117,7 @@ func TestNewForwardsConfigAndMethods(t *testing.T) {
func TestNewWrapsFactoryError(t *testing.T) {
name := "direct-test-error"
transport.Register(name, func(context.Context, transport.Config) (transport.Transport, error) {
return nil, errors.New("boom")
return nil, errDirectBoom
})
_, err := New(context.Background(), link.Config{Transport: name})
@@ -120,9 +128,9 @@ func TestNewWrapsFactoryError(t *testing.T) {
func TestDirectLinkWrapsTransportErrors(t *testing.T) {
ln := &directLink{transport: &stubTransport{
connectErr: errors.New("connect boom"),
sendErr: errors.New("send boom"),
closeErr: errors.New("close boom"),
connectErr: errDirectConnectBoom,
sendErr: errDirectSendBoom,
closeErr: errDirectCloseBoom,
}}
if err := ln.Connect(context.Background()); err == nil || err.Error() != "transport connect: connect boom" {

View File

@@ -55,7 +55,7 @@ type Config struct {
// Factory creates a link instance.
type Factory func(ctx context.Context, cfg Config) (Link, error)
var registry = make(map[string]Factory)
var registry = make(map[string]Factory) //nolint:gochecknoglobals // package-level state intentional
// Register adds a link factory to the registry.
func Register(name string, factory Factory) {

View File

@@ -7,7 +7,7 @@ import (
)
// verboseEnabled controls whether verbose and debug logging is enabled.
var verboseEnabled atomic.Bool
var verboseEnabled atomic.Bool //nolint:gochecknoglobals // package-level state intentional
// SetVerbose enables or disables verbose/debug logging.
func SetVerbose(enabled bool) {

View File

@@ -12,6 +12,8 @@ import (
cryptopkg "github.com/openlibrecommunity/olcrtc/internal/crypto"
)
var errMuxBoom = errors.New("boom")
type stubLink struct {
mu sync.Mutex
canSend bool
@@ -163,7 +165,7 @@ func TestWriteReturnsErrClosedWhileWaiting(t *testing.T) {
func TestWriteWrapsSendError(t *testing.T) {
cipher := newTestCipher(t)
conn := New(&stubLink{canSend: true, sendErr: errors.New("boom")}, cipher)
conn := New(&stubLink{canSend: true, sendErr: errMuxBoom}, cipher)
_, err := conn.Write([]byte("payload"))
if err == nil || err.Error() != "send: boom" {

View File

@@ -18,8 +18,8 @@ var embeddedNames string
var embeddedSurnames string
var (
firstNames = parseEmbedded(embeddedNames)
lastNames = parseEmbedded(embeddedSurnames)
firstNames = parseEmbedded(embeddedNames) //nolint:gochecknoglobals // package-level state intentional
lastNames = parseEmbedded(embeddedSurnames) //nolint:gochecknoglobals // package-level state intentional
)
func parseEmbedded(raw string) []string {
@@ -35,7 +35,7 @@ func parseEmbedded(raw string) []string {
}
func loadNames(path string) ([]string, error) {
file, err := os.Open(path)
file, err := os.Open(path) //nolint:gosec // G304: opens internal asset bundled with the binary
if err != nil {
return nil, fmt.Errorf("open names file %q: %w", path, err)
}

View File

@@ -75,7 +75,7 @@ func TestGenerateFallsBackWhenNamesEmpty(t *testing.T) {
}
func TestRandomIndexBounds(t *testing.T) {
for i := 0; i < 20; i++ {
for range 20 {
got := randomIndex(2)
if got < 0 || got > 1 {
t.Fatalf("randomIndex(2) = %d, out of range", got)

View File

@@ -12,7 +12,7 @@ import (
// Protector is called with a socket file descriptor before connect.
// On Android, this calls VpnService.protect(fd) to bypass VPN routing.
var Protector func(fd int) bool
var Protector func(fd int) bool //nolint:gochecknoglobals // package-level state intentional
func controlFunc(network, _ string, c syscall.RawConn) error {
if Protector == nil {

View File

@@ -10,6 +10,8 @@ import (
"time"
)
var errProtectBoom = errors.New("boom")
type rawConnStub struct {
controlFn func(func(uintptr)) error
}
@@ -67,13 +69,14 @@ func TestControlFuncWrapsControlError(t *testing.T) {
t.Cleanup(func() { Protector = old })
err := controlFunc("tcp4", "", rawConnStub{
controlFn: func(func(uintptr)) error { return errors.New("boom") },
controlFn: func(func(uintptr)) error { return errProtectBoom },
})
if err == nil || err.Error() != "control failed: boom" {
t.Fatalf("controlFunc() error = %v", err)
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestNewDialerAndHTTPClient(t *testing.T) {
dialer := NewDialer()
if dialer.Timeout != 10*time.Second || dialer.KeepAlive != 30*time.Second || dialer.Control == nil {
@@ -93,7 +96,8 @@ func TestNewDialerAndHTTPClient(t *testing.T) {
}
func TestDialContextAndProxyDialer(t *testing.T) {
ln, err := net.Listen("tcp4", "127.0.0.1:0")
var lc net.ListenConfig
ln, err := lc.Listen(context.Background(), "tcp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("Listen() error = %v", err)
}

View File

@@ -20,7 +20,7 @@ const (
contentTypeJSON = "application/json"
)
var apiBase = "https://bk.salutejazz.ru"
var apiBase = "https://bk.salutejazz.ru" //nolint:gochecknoglobals // package-level state intentional
// RoomInfo contains connection details for a SaluteJazz room.
type RoomInfo struct {

View File

@@ -10,7 +10,7 @@ import (
"testing"
)
func withJazzAPIServer(t *testing.T, h http.Handler) string {
func withJazzAPIServer(t *testing.T, h http.Handler) {
t.Helper()
old := apiBase
srv := httptest.NewServer(h)
@@ -19,25 +19,25 @@ func withJazzAPIServer(t *testing.T, h http.Handler) string {
srv.Close()
})
apiBase = srv.URL
return srv.URL
}
//nolint:cyclop // table-driven test naturally has many branches
func TestCreateMeetingAndPreconnect(t *testing.T) {
withJazzAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get(headerAuthType) != authTypeAnonymous {
t.Fatalf("missing auth header: %v", r.Header)
}
switch r.URL.Path {
case "/room/create-meeting":
case "/room/create-meeting": //nolint:goconst // test literal, repetition is intentional
if r.Method != http.MethodPost {
t.Fatalf("create method = %s", r.Method)
}
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "room-1", Password: "pass"})
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "room-1", Password: "pass"}) //nolint:gosec,lll // G117: test-only struct mirroring upstream API shape
case "/room/room-1/preconnect":
if r.Method != http.MethodPost {
t.Fatalf("preconnect method = %s", r.Method)
}
_ = json.NewEncoder(w).Encode(map[string]string{"connectorUrl": "wss://connector"})
_ = json.NewEncoder(w).Encode(map[string]string{"connectorUrl": "wss://connector"}) //nolint:goconst,lll // test literal, repetition is intentional
default:
http.NotFound(w, r)
}
@@ -64,11 +64,12 @@ func TestCreateMeetingAndPreconnect(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestCreateRoomAndJoinRoom(t *testing.T) {
withJazzAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/room/create-meeting":
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "new-room", Password: "new-pass"})
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "new-room", Password: "new-pass"}) //nolint:goconst,gosec,lll // test literal; G117 is a false positive for test fixtures
case "/room/new-room/preconnect", "/room/existing/preconnect":
_ = json.NewEncoder(w).Encode(map[string]string{"connectorUrl": "wss://connector"})
default:
@@ -115,7 +116,7 @@ func TestNewPeerUsesRoomAPI(t *testing.T) {
withJazzAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/room/create-meeting":
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "new-room", Password: "new-pass"})
_ = json.NewEncoder(w).Encode(createResponse{RoomID: "new-room", Password: "new-pass"}) //nolint:gosec,lll // G117: test-only struct mirroring upstream API shape
case "/room/new-room/preconnect", "/room/existing/preconnect":
_ = json.NewEncoder(w).Encode(map[string]string{"connectorUrl": "wss://connector"})
default:

View File

@@ -16,7 +16,7 @@ func encodeVarint(value uint64) []byte {
}
func encodeField(fieldNumber int, wireType int, data []byte) []byte {
tag := encodeVarint(uint64(fieldNumber)<<3 | uint64(wireType))
tag := encodeVarint(uint64(fieldNumber)<<3 | uint64(wireType)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
switch wireType {
case 2:
length := encodeVarint(uint64(len(data)))
@@ -101,12 +101,12 @@ func handleWireType(reader *byteReader, wireType int, dataLen int) ([]byte, bool
if err != nil {
return nil, false
}
if length > uint64(dataLen)-uint64(reader.pos) {
if length > uint64(dataLen)-uint64(reader.pos) { //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
return nil, false
}
fieldData := make([]byte, length)
n, err := reader.Read(fieldData)
if err != nil || uint64(n) != length {
if err != nil || uint64(n) != length { //nolint:gosec // G115: bounded conversion verified by surrounding logic
return nil, false
}
return fieldData, true

View File

@@ -9,6 +9,7 @@ import (
"github.com/pion/webrtc/v4"
)
//nolint:cyclop // table-driven test naturally has many branches
func TestPeerStateHelpers(t *testing.T) {
p := &Peer{
reconnectCh: make(chan struct{}, 1),

View File

@@ -13,10 +13,15 @@ import (
"github.com/openlibrecommunity/olcrtc/internal/protect"
)
//nolint:gochecknoglobals // overridable base URL for tests
var apiBase = "https://cloud-api.yandex.ru/telemost_front/v2/telemost"
// ErrAPI marks failures returned by the Telemost HTTP API.
var ErrAPI = errors.New("api error")
// ConnectionInfo describes the connection metadata returned by the Telemost API.
//
//nolint:tagliatelle // wire format dictated by the upstream Telemost API
type ConnectionInfo struct {
RoomID string `json:"room_id"`
PeerID string `json:"peer_id"`
@@ -26,6 +31,7 @@ type ConnectionInfo struct {
} `json:"client_configuration"`
}
// GetConnectionInfo fetches connection metadata for the given Telemost room URL.
func GetConnectionInfo(ctx context.Context, roomURL, displayName string) (*ConnectionInfo, error) {
u := fmt.Sprintf("%s/conferences/%s/connection", apiBase, url.QueryEscape(roomURL))

View File

@@ -33,9 +33,9 @@ func TestGetConnectionInfo(t *testing.T) {
t.Fatalf("display_name query = %q", r.URL.Query().Get("display_name"))
}
_ = json.NewEncoder(w).Encode(ConnectionInfo{
RoomID: "room",
PeerID: "peer-id",
Credentials: "creds",
RoomID: "room", //nolint:goconst // test literal, repetition is intentional
PeerID: "peer-id", //nolint:goconst // test literal, repetition is intentional
Credentials: "creds", //nolint:goconst // test literal, repetition is intentional
})
}))
@@ -49,14 +49,14 @@ func TestGetConnectionInfo(t *testing.T) {
}
func TestGetConnectionInfoErrors(t *testing.T) {
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
http.Error(w, "bad", http.StatusForbidden)
}))
if _, err := GetConnectionInfo(context.Background(), "room", "peer"); !errors.Is(err, ErrAPI) {
t.Fatalf("GetConnectionInfo() error = %v, want %v", err, ErrAPI)
}
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write([]byte("{"))
}))
if _, err := GetConnectionInfo(context.Background(), "room", "peer"); err == nil {
@@ -65,7 +65,7 @@ func TestGetConnectionInfoErrors(t *testing.T) {
}
func TestTelemostNewPeerUsesConnectionInfo(t *testing.T) {
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
withTelemostAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_ = json.NewEncoder(w).Encode(ConnectionInfo{
RoomID: "room",
PeerID: "peer-id",

View File

@@ -1469,7 +1469,7 @@ func (p *Peer) calculateDelay() time.Duration {
if maxDelay <= minDelay {
return minDelay
}
return minDelay + time.Duration(rand.Int64N(int64(maxDelay-minDelay)))
return minDelay + time.Duration(rand.Int64N(int64(maxDelay-minDelay))) //nolint:gosec,lll // G404: non-cryptographic shaping randomness
}
// CanSend checks if data can be sent.

View File

@@ -34,7 +34,7 @@ func TestTrafficShapeAndDelay(t *testing.T) {
}
p.SetTrafficShape(TrafficShape{MaxMessageSize: 10, MinDelay: time.Millisecond, MaxDelay: 4 * time.Millisecond})
for i := 0; i < 20; i++ {
for range 20 {
got := p.calculateDelay()
if got < time.Millisecond || got >= 4*time.Millisecond {
t.Fatalf("calculateDelay() = %v, out of range", got)
@@ -50,7 +50,7 @@ func TestICEParsingFiltersTURN(t *testing.T) {
t.Fatal("isNonTURNURL rejected STUN URL")
}
urls := parseICEURLs(map[string]interface{}{"urls": []interface{}{"turn:x", "stun:a", 123, "turns:y"}})
urls := parseICEURLs(map[string]interface{}{"urls": []interface{}{"turn:x", "stun:a", 123, "turns:y"}}) //nolint:goconst,lll // test literal, repetition is intentional
if len(urls) != 1 || urls[0] != "stun:a" {
t.Fatalf("parseICEURLs(interface) = %v, want [stun:a]", urls)
}
@@ -85,7 +85,7 @@ func TestParseICEServer(t *testing.T) {
func TestConferenceEndParsing(t *testing.T) {
for _, msg := range []map[string]interface{}{
{"conferenceClosed": true},
{"conference": map[string]interface{}{"state": "ENDED"}},
{"conference": map[string]interface{}{"state": "ENDED"}}, //nolint:goconst // test literal, repetition is intentional
{"conferenceState": map[string]interface{}{"state": "terminated"}},
} {
if !isConferenceEndMessage(msg) {
@@ -106,6 +106,7 @@ func TestConferenceEndParsing(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestPeerSmallStateHelpers(t *testing.T) {
p := &Peer{
reconnectCh: make(chan struct{}, 1),
@@ -169,7 +170,7 @@ func TestTelemetryCfgParsing(t *testing.T) {
t.Fatal("parseTelemetryCfg() accepted missing config")
}
if _, _, ok := parseTelemetryCfg(map[string]interface{}{
"telemetryConfiguration": map[string]interface{}{},
"telemetryConfiguration": map[string]interface{}{}, //nolint:goconst // test literal, repetition is intentional
}); ok {
t.Fatal("parseTelemetryCfg() accepted missing endpoint")
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/pion/webrtc/v4"
)
//nolint:cyclop // table-driven test naturally has many branches
func TestTelemostProviderForwardsPeerMethods(t *testing.T) {
peer := &Peer{
reconnectCh: make(chan struct{}, 1),

View File

@@ -5,6 +5,7 @@ import (
"time"
)
//nolint:cyclop // table-driven test naturally has many branches
func TestSessionReconnectAndEndedHelpers(t *testing.T) {
p := &Peer{
reconnectCh: make(chan struct{}, 2),

View File

@@ -12,7 +12,7 @@ import (
"github.com/openlibrecommunity/olcrtc/internal/protect"
)
var apiBase = "https://stream.wb.ru"
var apiBase = "https://stream.wb.ru" //nolint:gochecknoglobals // package-level state intentional
var (
errGuestRegister = errors.New("guest register failed")

View File

@@ -20,6 +20,7 @@ func withWBAPIServer(t *testing.T, h http.Handler) {
apiBase = srv.URL
}
//nolint:cyclop // table-driven test naturally has many branches
func TestWBStreamAPIHappyPath(t *testing.T) {
withWBAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
@@ -27,20 +28,20 @@ func TestWBStreamAPIHappyPath(t *testing.T) {
if r.Method != http.MethodPost {
t.Fatalf("guest method = %s", r.Method)
}
_ = json.NewEncoder(w).Encode(guestRegisterResponse{AccessToken: "access"})
_ = json.NewEncoder(w).Encode(guestRegisterResponse{AccessToken: "access"}) //nolint:goconst,gosec,lll // test literal; G117 is a false positive for test fixtures
case "/api-room/api/v2/room":
if r.Header.Get("Authorization") != "Bearer access" {
t.Fatalf("room auth = %q", r.Header.Get("Authorization"))
}
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(createRoomResponse{RoomID: "room"})
_ = json.NewEncoder(w).Encode(createRoomResponse{RoomID: "room"}) //nolint:goconst,lll // test literal, repetition is intentional
case "/api-room/api/v1/room/room/join":
w.WriteHeader(http.StatusOK)
case "/api-room-manager/api/v1/room/room/token":
if r.URL.Query().Get("displayName") != "peer" {
t.Fatalf("displayName query = %q", r.URL.Query().Get("displayName"))
}
_ = json.NewEncoder(w).Encode(tokenResponse{RoomToken: "token"})
_ = json.NewEncoder(w).Encode(tokenResponse{RoomToken: "token"}) //nolint:goconst,lll // test literal, repetition is intentional
default:
http.NotFound(w, r)
}
@@ -75,7 +76,7 @@ func TestWBStreamAPIHappyPath(t *testing.T) {
}
func TestWBStreamAPIErrors(t *testing.T) {
withWBAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
withWBAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
http.Error(w, "bad", http.StatusBadGateway)
}))
@@ -97,7 +98,7 @@ func TestWBStreamGetRoomToken(t *testing.T) {
withWBAPIServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/auth/api/v1/auth/user/guest-register":
_ = json.NewEncoder(w).Encode(guestRegisterResponse{AccessToken: "access"})
_ = json.NewEncoder(w).Encode(guestRegisterResponse{AccessToken: "access"}) //nolint:gosec,lll // G117: test-only struct mirroring upstream API shape
case "/api-room/api/v2/room":
_ = json.NewEncoder(w).Encode(createRoomResponse{RoomID: "created"})
case "/api-room/api/v1/room/created/join":

View File

@@ -13,7 +13,7 @@ func TestNewPeerAndSimpleAccessors(t *testing.T) {
if err != nil {
t.Fatalf("NewPeer() error = %v", err)
}
if p.roomURL != "room" || p.name != "name" || p.sendQueue == nil || p.done == nil {
if p.roomURL != "room" || p.name != "name" || p.sendQueue == nil || p.done == nil { //nolint:goconst,lll // test literal, repetition is intentional
t.Fatalf("NewPeer() = %+v", p)
}
if p.GetSendQueue() != p.sendQueue {

View File

@@ -8,6 +8,7 @@ import (
"github.com/pion/webrtc/v4"
)
//nolint:cyclop // table-driven test naturally has many branches
func TestWBStreamProviderForwardsPeerMethods(t *testing.T) {
peer, err := NewPeer(context.Background(), "room", "name", nil)
if err != nil {

View File

@@ -481,7 +481,7 @@ func (s *Server) socks5Connect(conn net.Conn, targetAddr string, targetPort int)
req := make([]byte, 0, 7+addrLen)
req = append(req, 5, 1, 0, 3, byte(addrLen))
req = append(req, []byte(targetAddr)...)
req = append(req, byte(targetPort>>8), byte(targetPort))
req = append(req, byte(targetPort>>8), byte(targetPort)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
if _, err := conn.Write(req); err != nil {
return fmt.Errorf("failed to write socks5 connect req: %w", err)

View File

@@ -48,8 +48,8 @@ func TestSmuxConfig(t *testing.T) {
func TestParseConnectRequest(t *testing.T) {
buf, err := json.Marshal(ConnectRequest{
Cmd: "connect",
ClientID: "client-1",
Addr: "example.com",
ClientID: "client-1", //nolint:goconst // test literal, repetition is intentional
Addr: "example.com", //nolint:goconst // test literal, repetition is intentional
Port: 443,
})
if err != nil {
@@ -82,6 +82,7 @@ func TestAuthorizeRequest(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestSocks5ConnectSuccess(t *testing.T) {
s := &Server{}
server, client := net.Pipe()
@@ -191,7 +192,7 @@ func TestSetupResolver(t *testing.T) {
}
}
func TestOnDataWithNilConn(t *testing.T) {
func TestOnDataWithNilConn(_ *testing.T) {
s := &Server{}
s.onData([]byte("ignored"))
}
@@ -227,7 +228,8 @@ func TestShutdownClosesLinkAndConn(t *testing.T) {
}
func TestDialWithoutProxy(t *testing.T) {
ln, err := net.Listen("tcp4", "127.0.0.1:0")
var lc net.ListenConfig
ln, err := lc.Listen(context.Background(), "tcp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("Listen() error = %v", err)
}
@@ -242,7 +244,10 @@ func TestDialWithoutProxy(t *testing.T) {
}
}()
tcpAddr := ln.Addr().(*net.TCPAddr)
tcpAddr, ok := ln.Addr().(*net.TCPAddr)
if !ok {
t.Fatalf("listener addr type = %T, want *net.TCPAddr", ln.Addr())
}
s := &Server{resolver: net.DefaultResolver}
conn, err := s.dial(ConnectRequest{Addr: "127.0.0.1", Port: tcpAddr.Port})
if err != nil {
@@ -254,7 +259,7 @@ func TestDialWithoutProxy(t *testing.T) {
func TestDialProxyError(t *testing.T) {
s := &Server{socksProxyAddr: "127.0.0.1", socksProxyPort: 1}
if _, err := s.dial(ConnectRequest{Addr: "example.com", Port: 443}); err == nil || !strings.Contains(err.Error(), "failed to dial proxy") {
if _, err := s.dial(ConnectRequest{Addr: "example.com", Port: 443}); err == nil || !strings.Contains(err.Error(), "failed to dial proxy") { //nolint:lll // long test description
t.Fatalf("dial() error = %v", err)
}
}

View File

@@ -9,6 +9,14 @@ import (
"github.com/openlibrecommunity/olcrtc/internal/transport"
)
var (
errDCBoom = errors.New("boom")
errDCOpenBoom = errors.New("open boom")
errDCConnectBoom = errors.New("connect boom")
errDCSendBoom = errors.New("send boom")
errDCCloseBoom = errors.New("close boom")
)
type stubSession struct {
stream carrier.ByteStream
streamErr error
@@ -54,6 +62,7 @@ func (s *stubByteStream) SetEndedCallback(cb func(string)) { s.endedCB = cb }
func (s *stubByteStream) WatchConnection(context.Context) { s.watched = true }
func (s *stubByteStream) CanSend() bool { return s.canSend }
//nolint:cyclop // table-driven test naturally has many branches
func TestNewAndFeatures(t *testing.T) {
stream := &stubByteStream{canSend: true}
carrier.Register("datachannel-test-new-and-features", func(context.Context, carrier.Config) (carrier.Session, error) {
@@ -89,7 +98,7 @@ func TestNewAndFeatures(t *testing.T) {
}
features := tr.Features()
if !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize != defaultMaxPayloadSize {
if !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize != defaultMaxPayloadSize { //nolint:lll // long test description
t.Fatalf("Features() = %+v", features)
}
if err := tr.Close(); err != nil {
@@ -99,32 +108,32 @@ func TestNewAndFeatures(t *testing.T) {
func TestNewErrorPaths(t *testing.T) {
carrier.Register("datachannel-fail-create", func(context.Context, carrier.Config) (carrier.Session, error) {
return nil, errors.New("boom")
return nil, errDCBoom
})
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-fail-create"}); err == nil || err.Error() != "create carrier transport: boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-fail-create"}); err == nil || err.Error() != "create carrier transport: boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
carrier.Register("datachannel-no-stream", func(context.Context, carrier.Config) (carrier.Session, error) {
return &nonByteStreamSession{}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-no-stream"}); !errors.Is(err, carrier.ErrByteStreamUnsupported) {
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-no-stream"}); !errors.Is(err, carrier.ErrByteStreamUnsupported) { //nolint:lll // long test description
t.Fatalf("New() error = %v, want %v", err, carrier.ErrByteStreamUnsupported)
}
carrier.Register("datachannel-open-stream-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return &stubSession{streamErr: errors.New("open boom")}, nil
return &stubSession{streamErr: errDCOpenBoom}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-open-stream-fails"}); err == nil || err.Error() != "open byte stream: open boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "datachannel-open-stream-fails"}); err == nil || err.Error() != "open byte stream: open boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
}
func TestStreamTransportWrapsErrors(t *testing.T) {
tr := &streamTransport{stream: &stubByteStream{
connectErr: errors.New("connect boom"),
sendErr: errors.New("send boom"),
closeErr: errors.New("close boom"),
connectErr: errDCConnectBoom,
sendErr: errDCSendBoom,
closeErr: errDCCloseBoom,
}}
if err := tr.Connect(context.Background()); err == nil || err.Error() != "stream connect: connect boom" {

View File

@@ -24,15 +24,18 @@ var (
// ErrSEIValueTruncated is returned when reading a SEI length-value runs past the buffer.
ErrSEIValueTruncated = errors.New("sei value truncated")
videoSEIUUID = [16]byte{
videoSEIUUID = [16]byte{ //nolint:gochecknoglobals // package-level state intentional
0x5d, 0xc0, 0x3b, 0xa8,
0x45, 0x0f,
0x4b, 0x55,
0x9a, 0x77,
0x1f, 0x91, 0x6c, 0x5b, 0x07, 0x39,
}
//nolint:gochecknoglobals // hardcoded H264 constants
baseSPS = mustDecodeHex("6742c00addec0440000003004000000300a3c489e0")
//nolint:gochecknoglobals // hardcoded H264 constants
basePPS = mustDecodeHex("68ce0fc8")
//nolint:gochecknoglobals // hardcoded H264 constants
baseIDR = mustDecodeHex("6588843a2628000902e0")
)
@@ -142,10 +145,11 @@ func appendSEIValue(dst []byte, value int) []byte {
dst = append(dst, 0xff)
value -= 0xff
}
return append(dst, byte(value))
return append(dst, byte(value)) //nolint:gosec // G115: bounded conversion verified by surrounding logic
}
func consumeSEIValue(data []byte, pos int) (value, next int, err error) {
func consumeSEIValue(data []byte, pos int) (int, int, error) {
value := 0
for {
if pos >= len(data) {
return 0, pos, ErrSEIValueTruncated
@@ -196,7 +200,6 @@ func unescapeRBSP(rbsp []byte) []byte {
func mustDecodeHex(value string) []byte {
data, err := hex.DecodeString(value)
if err != nil {
//nolint:forbidigo // hardcoded constant; failure indicates a corrupt binary
panic(errors.Join(ErrInvalidH264Constant, err))
}
return data

View File

@@ -21,7 +21,7 @@ func TestInboundAssemblyAndAck(t *testing.T) {
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)),
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 1,
fragTotal: 2,
payload: []byte(" world"),
@@ -34,7 +34,7 @@ func TestInboundAssemblyAndAck(t *testing.T) {
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)),
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 0,
fragTotal: 2,
payload: []byte("hello"),
@@ -57,7 +57,7 @@ func TestInboundAssemblyAndAck(t *testing.T) {
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)),
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 0,
fragTotal: 2,
payload: []byte("hello"),

View File

@@ -352,11 +352,9 @@ func (p *streamTransport) writeBatch(idle []byte) bool {
if i > 0 {
return true
}
//nolint:errcheck,gosec // best-effort idle keepalive frame
_ = p.track.WriteSample(media.Sample{Data: idle, Duration: frameInterval})
return true
}
//nolint:errcheck,gosec // best-effort sample write
_ = p.track.WriteSample(media.Sample{Data: buildVideoAccessUnit(payload), Duration: frameInterval})
}
return true
@@ -474,7 +472,7 @@ func (p *streamTransport) assembleMessage(msg *inboundMessage) []byte {
for _, frag := range msg.frags {
data = append(data, frag...)
}
if uint32(len(data)) > msg.totalLen {
if uint32(len(data)) > msg.totalLen { //nolint:gosec // G115: bounded conversion verified by surrounding logic
data = data[:msg.totalLen]
}
return data
@@ -515,7 +513,6 @@ func (p *streamTransport) handleInboundFrame(frame transportFrame) {
}
func (p *streamTransport) sendAck(seq, crc uint32) {
//nolint:dogsled,errcheck // ack delivery is best-effort
_ = p.enqueueFrame(encodeAckFrame(seq, crc), true)
}
@@ -558,9 +555,9 @@ func encodeDataFrame(seq, crc uint32, totalLen, fragIdx, fragTotal int, payload
out[5] = frameTypeData
binary.BigEndian.PutUint32(out[6:10], seq)
binary.BigEndian.PutUint32(out[10:14], crc)
binary.BigEndian.PutUint32(out[14:18], uint32(totalLen))
binary.BigEndian.PutUint16(out[18:20], uint16(fragIdx))
binary.BigEndian.PutUint16(out[20:22], uint16(fragTotal))
binary.BigEndian.PutUint32(out[14:18], uint32(totalLen)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.BigEndian.PutUint16(out[18:20], uint16(fragIdx)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.BigEndian.PutUint16(out[20:22], uint16(fragTotal)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
copy(out[22:], payload)
return out
}

View File

@@ -65,6 +65,7 @@ type nonVideoSession struct{}
func (s *nonVideoSession) Capabilities() carrier.Capabilities { return carrier.Capabilities{} }
//nolint:cyclop // table-driven test naturally has many branches
func TestNewConnectCallbacksAndFeatures(t *testing.T) {
stream := &fakeVideoStream{canSend: true}
name := "seichannel-unit-new"
@@ -105,7 +106,7 @@ func TestNewConnectCallbacksAndFeatures(t *testing.T) {
if !tr.CanSend() {
t.Fatal("CanSend() = false, want true")
}
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 {
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 { //nolint:lll // long test description
t.Fatalf("Features() = %+v", features)
}
if tr.fragmentSize != 512 || tr.batchSize != 3 || tr.frameInterval != 25*time.Millisecond ||
@@ -122,21 +123,21 @@ func TestNewErrorPaths(t *testing.T) {
carrier.Register("seichannel-create-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return nil, errBoom
})
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
carrier.Register("seichannel-no-video", func(context.Context, carrier.Config) (carrier.Session, error) {
return &nonVideoSession{}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) {
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) { //nolint:lll // long test description
t.Fatalf("New() error = %v, want %v", err, ErrVideoTrackUnsupported)
}
carrier.Register("seichannel-open-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return &fakeVideoSession{err: errOpenBoom}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-open-fails"}); err == nil || err.Error() != "open video track: open boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "seichannel-open-fails"}); err == nil || err.Error() != "open video track: open boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
}

View File

@@ -63,7 +63,7 @@ type Config struct {
// Factory creates a transport instance.
type Factory func(ctx context.Context, cfg Config) (Transport, error)
var registry = make(map[string]Factory)
var registry = make(map[string]Factory) //nolint:gochecknoglobals // package-level state intentional
// Register adds a transport factory to the registry.
func Register(name string, factory Factory) {

View File

@@ -202,7 +202,7 @@ func newFFmpegEncoder(
vcodec := resolveEncoderCodec(spec, hw)
args := buildEncoderArgs(spec, vcodec, width, height, fps, bitrate)
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
cmd := exec.CommandContext(ctx, "ffmpeg", args...) //nolint:gosec,lll // G204: ffmpeg path is operator-controlled config, not user input
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("encoder stdin: %w", err)
@@ -404,7 +404,7 @@ func newFFmpegDecoder(
decoderName := resolveDecoderName(spec, hw)
args := buildDecoderArgs(spec, decoderName, width, height, "gray")
cmd := exec.CommandContext(ctx, "ffmpeg", args...)
cmd := exec.CommandContext(ctx, "ffmpeg", args...) //nolint:gosec,lll // G204: ffmpeg path is operator-controlled config, not user input
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("decoder stdin: %w", err)
@@ -539,9 +539,9 @@ func writeIVFHeader(w io.Writer, fourCC string, width, height, frameRate int) er
binary.LittleEndian.PutUint16(header[4:6], 0)
binary.LittleEndian.PutUint16(header[6:8], 32)
copy(header[8:12], []byte(fourCC))
binary.LittleEndian.PutUint16(header[12:14], uint16(width))
binary.LittleEndian.PutUint16(header[14:16], uint16(height))
binary.LittleEndian.PutUint32(header[16:20], uint32(frameRate))
binary.LittleEndian.PutUint16(header[12:14], uint16(width)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.LittleEndian.PutUint16(header[14:16], uint16(height)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.LittleEndian.PutUint32(header[16:20], uint32(frameRate)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.LittleEndian.PutUint32(header[20:24], 1)
binary.LittleEndian.PutUint32(header[24:28], 0)
binary.LittleEndian.PutUint32(header[28:32], 0)
@@ -550,7 +550,7 @@ func writeIVFHeader(w io.Writer, fourCC string, width, height, frameRate int) er
func writeIVFFrame(w io.Writer, pts uint64, frame []byte) error {
header := make([]byte, 12)
binary.LittleEndian.PutUint32(header[0:4], uint32(len(frame)))
binary.LittleEndian.PutUint32(header[0:4], uint32(len(frame))) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.LittleEndian.PutUint64(header[4:12], pts)
if err := writeAll(w, header); err != nil {
return err

View File

@@ -71,9 +71,9 @@ func encodeDataFrame(seq, crc uint32, totalLen, fragIdx, fragTotal int, payload
out[5] = frameTypeData
binary.BigEndian.PutUint32(out[6:10], seq)
binary.BigEndian.PutUint32(out[10:14], crc)
binary.BigEndian.PutUint32(out[14:18], uint32(totalLen))
binary.BigEndian.PutUint16(out[18:20], uint16(fragIdx))
binary.BigEndian.PutUint16(out[20:22], uint16(fragTotal))
binary.BigEndian.PutUint32(out[14:18], uint32(totalLen)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.BigEndian.PutUint16(out[18:20], uint16(fragIdx)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
binary.BigEndian.PutUint16(out[20:22], uint16(fragTotal)) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
copy(out[22:], payload)
return out
}

View File

@@ -11,6 +11,11 @@ import (
"github.com/pion/webrtc/v4"
)
var (
errVideoFrameBase = errors.New("base")
errVideoFrameBoom = errors.New("boom")
)
func TestFragmentPayload(t *testing.T) {
frags := fragmentPayload([]byte("abcdef"), 2)
want := [][]byte{[]byte("ab"), []byte("cd"), []byte("ef")}
@@ -56,6 +61,7 @@ func TestDecodeTransportFrameErrorsAndAck(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestCodecSpecsAndArgs(t *testing.T) {
for _, mime := range []string{webrtc.MimeTypeH264, webrtc.MimeTypeVP8, webrtc.MimeTypeVP9} {
spec, ok := codecSpecForMime(mime)
@@ -79,7 +85,7 @@ func TestCodecSpecsAndArgs(t *testing.T) {
if got := resolveEncoderCodec(vp9CodecSpec(), "nvenc"); got != "vp9_nvenc" {
t.Fatalf("resolveEncoderCodec(vp9,nvenc) = %q", got)
}
if got := resolveEncoderCodec(codecSpec{mimeType: webrtc.MimeTypeAV1, encoder: "libaom-av1"}, "nvenc"); got != "av1_nvenc" {
if got := resolveEncoderCodec(codecSpec{mimeType: webrtc.MimeTypeAV1, encoder: "libaom-av1"}, "nvenc"); got != "av1_nvenc" { //nolint:lll // long test description
t.Fatalf("resolveEncoderCodec(av1,nvenc) = %q", got)
}
@@ -140,6 +146,7 @@ type bufferWriteCloser struct {
func (w *bufferWriteCloser) Close() error { return nil }
//nolint:cyclop // table-driven test naturally has many branches
func TestIVFWritersAndWithStderr(t *testing.T) {
var buf bytes.Buffer
if err := writeIVFHeader(&buf, "VP80", 320, 240, 30); err != nil {
@@ -164,7 +171,7 @@ func TestIVFWritersAndWithStderr(t *testing.T) {
t.Fatalf("writeAll(errWriter) error = %v", err)
}
baseErr := errors.New("base")
baseErr := errVideoFrameBase
if got := withStderr(baseErr, bytes.NewBufferString(" details \n")); got == nil || got.Error() != "base: details" {
t.Fatalf("withStderr() = %v", got)
}
@@ -182,13 +189,13 @@ func TestFFmpegProcessErrAndFrameValidation(t *testing.T) {
if _, err := enc.EncodeFrame([]byte("bad")); !errors.Is(err, ErrUnexpectedFrameSize) {
t.Fatalf("EncodeFrame(short) error = %v, want %v", err, ErrUnexpectedFrameSize)
}
enc.setErr(errors.New("boom"))
enc.setErr(errVideoFrameBoom)
if _, err := enc.EncodeFrame([]byte("good")); err == nil || !strings.Contains(err.Error(), "encoder failed") {
t.Fatalf("EncodeFrame(processErr) error = %v", err)
}
dec := &ffmpegDecoder{stderr: bytes.NewBufferString("decoder failed")}
dec.setErr(errors.New("boom"))
dec.setErr(errVideoFrameBoom)
if err := dec.PushSample([]byte("sample")); err == nil || !strings.Contains(err.Error(), "decoder failed") {
t.Fatalf("PushSample(processErr) error = %v", err)
}
@@ -199,6 +206,7 @@ func TestFFmpegProcessErrAndFrameValidation(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestFFmpegReadersAndSampleWriters(t *testing.T) {
var ivf bytes.Buffer
if err := writeIVFHeader(&ivf, "VP80", 2, 2, 30); err != nil {

View File

@@ -21,7 +21,7 @@ func TestInboundAssemblyAndAck(t *testing.T) {
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)),
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 1,
fragTotal: 2,
payload: []byte(" video"),
@@ -34,7 +34,7 @@ func TestInboundAssemblyAndAck(t *testing.T) {
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)),
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 0,
fragTotal: 2,
payload: []byte("hello"),

View File

@@ -70,7 +70,7 @@ type streamTransport struct {
videoCodec string
videoTileModule int
videoTileRS int
runCtx context.Context
runCtx context.Context //nolint:containedctx,lll // long-lived context drives idle-frame loops bound to this transport's lifetime
idleFrame []byte
idleFrameMu sync.Mutex
@@ -571,7 +571,7 @@ func (p *streamTransport) assembleMessage(msg *inboundMessage) []byte {
for _, frag := range msg.frags {
data = append(data, frag...)
}
if uint32(len(data)) > msg.totalLen {
if uint32(len(data)) > msg.totalLen { //nolint:gosec // G115: bounded conversion verified by surrounding logic
data = data[:msg.totalLen]
}
return data

View File

@@ -12,6 +12,11 @@ import (
"github.com/pion/webrtc/v4"
)
var (
errVideoUnitBoom = errors.New("boom")
errVideoUnitOpenBoom = errors.New("open boom")
)
type fakeVideoSession struct {
stream *fakeVideoStream
err error
@@ -55,6 +60,7 @@ type nonVideoSession struct{}
func (s *nonVideoSession) Capabilities() carrier.Capabilities { return carrier.Capabilities{} }
//nolint:cyclop // table-driven test naturally has many branches
func TestNewCallbacksFeaturesAndClose(t *testing.T) {
stream := &fakeVideoStream{canSend: true}
name := "videochannel-unit-new"
@@ -75,7 +81,10 @@ func TestNewCallbacksFeaturesAndClose(t *testing.T) {
if err != nil {
t.Fatalf("New() error = %v", err)
}
tr := trIface.(*streamTransport)
tr, ok := trIface.(*streamTransport)
if !ok {
t.Fatalf("transport type = %T, want *streamTransport", trIface)
}
if !stream.trackAdded || stream.trackCB == nil {
t.Fatal("New() did not attach track and handler")
}
@@ -89,7 +98,7 @@ func TestNewCallbacksFeaturesAndClose(t *testing.T) {
if !tr.CanSend() {
t.Fatal("CanSend() = false, want true")
}
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 {
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 { //nolint:lll // long test description
t.Fatalf("Features() = %+v", features)
}
if tr.videoQRSize != defaultFragmentSize || tr.videoTileModule != 4 || tr.videoTileRS != 20 {
@@ -102,23 +111,23 @@ func TestNewCallbacksFeaturesAndClose(t *testing.T) {
func TestNewErrorPaths(t *testing.T) {
carrier.Register("videochannel-create-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return nil, errors.New("boom")
return nil, errVideoUnitBoom
})
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
carrier.Register("videochannel-no-video", func(context.Context, carrier.Config) (carrier.Session, error) {
return &nonVideoSession{}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) {
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) { //nolint:lll // long test description
t.Fatalf("New() error = %v, want %v", err, ErrVideoTrackUnsupported)
}
carrier.Register("videochannel-open-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return &fakeVideoSession{err: errors.New("open boom")}, nil
return &fakeVideoSession{err: errVideoUnitOpenBoom}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-open-fails"}); err == nil || err.Error() != "open video track: open boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "videochannel-open-fails"}); err == nil || err.Error() != "open video track: open boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
}
@@ -160,6 +169,7 @@ func TestSendAckAndClosePaths(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestOutboundPriorityRenderAndClosedEnqueue(t *testing.T) {
tr := &streamTransport{
stream: &fakeVideoStream{canSend: true},

View File

@@ -129,7 +129,7 @@ func extractTilePayload(frame []byte, tileModule, tileRS int) ([]byte, error) {
result, err := c.Decode(frame)
if err != nil {
return nil, nil
return nil, nil //nolint:nilerr // decode failures are treated as "no payload" by callers
}
return result.Payload, nil

View File

@@ -134,7 +134,7 @@ func (r *kcpRuntime) send(msg []byte) error {
return ErrKCPMessageTooLarge
}
var hdr [kcpLenPrefix]byte
binary.BigEndian.PutUint32(hdr[:], uint32(len(msg)))
binary.BigEndian.PutUint32(hdr[:], uint32(len(msg))) //nolint:gosec,lll // G115: bounded conversion verified by surrounding logic
r.writeMu.Lock()
defer r.writeMu.Unlock()

View File

@@ -8,6 +8,7 @@ import (
"time"
)
//nolint:cyclop // table-driven test naturally has many branches
func TestKCPConnReadWriteDeadlinesAndClose(t *testing.T) {
out := make(chan []byte, 1)
hdr := testEpochHdr(9)

View File

@@ -62,7 +62,7 @@ var (
ErrTransportClosed = errors.New("vp8channel transport closed")
)
var vp8Keepalive = []byte{
var vp8Keepalive = []byte{ //nolint:gochecknoglobals // package-level state intentional
0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x10, 0x00,
0x10, 0x00, 0x00, 0x47, 0x08, 0x85, 0x85, 0x88,
0x99, 0x84, 0x88, 0xfc,
@@ -212,7 +212,7 @@ func randomEpoch() uint32 {
if _, err := rand.Read(b[:]); err != nil {
// rand.Read on Linux essentially never fails; fall back to a
// time-derived value rather than panic.
return uint32(time.Now().UnixNano())
return uint32(time.Now().UnixNano()) //nolint:gosec // G115: bounded conversion verified by surrounding logic
}
e := binary.BigEndian.Uint32(b[:])
if e == 0 {

View File

@@ -14,6 +14,11 @@ import (
"github.com/pion/webrtc/v4"
)
var (
errVP8UnitBoom = errors.New("boom")
errVP8UnitOpenBoom = errors.New("open boom")
)
type fakeVideoSession struct {
stream *fakeVideoStream
err error
@@ -77,6 +82,7 @@ type nonVideoSession struct{}
func (s *nonVideoSession) Capabilities() carrier.Capabilities { return carrier.Capabilities{} }
//nolint:cyclop // table-driven test naturally has many branches
func TestNewConnectSendCallbacksFeaturesAndClose(t *testing.T) {
stream := &fakeVideoStream{canSend: true}
name := "vp8channel-unit-new"
@@ -93,7 +99,10 @@ func TestNewConnectSendCallbacksFeaturesAndClose(t *testing.T) {
if err != nil {
t.Fatalf("New() error = %v", err)
}
tr := trIface.(*streamTransport)
tr, ok := trIface.(*streamTransport)
if !ok {
t.Fatalf("transport type = %T, want *streamTransport", trIface)
}
if !stream.trackAdded || stream.trackCB == nil {
t.Fatal("New() did not attach track and handler")
}
@@ -125,7 +134,7 @@ func TestNewConnectSendCallbacksFeaturesAndClose(t *testing.T) {
if !tr.CanSend() {
t.Fatal("CanSend() = false, want true")
}
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 {
if features := tr.Features(); !features.Reliable || !features.Ordered || !features.MessageOriented || features.MaxPayloadSize == 0 { //nolint:lll // long test description
t.Fatalf("Features() = %+v", features)
}
if err := tr.Send([]byte("payload")); err != nil {
@@ -142,27 +151,28 @@ func TestNewConnectSendCallbacksFeaturesAndClose(t *testing.T) {
func TestNewErrorPaths(t *testing.T) {
carrier.Register("vp8channel-create-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return nil, errors.New("boom")
return nil, errVP8UnitBoom
})
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-create-fails"}); err == nil || err.Error() != "create carrier transport: boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
carrier.Register("vp8channel-no-video", func(context.Context, carrier.Config) (carrier.Session, error) {
return &nonVideoSession{}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) {
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-no-video"}); !errors.Is(err, ErrVideoTrackUnsupported) { //nolint:lll // long test description
t.Fatalf("New() error = %v, want %v", err, ErrVideoTrackUnsupported)
}
carrier.Register("vp8channel-open-fails", func(context.Context, carrier.Config) (carrier.Session, error) {
return &fakeVideoSession{err: errors.New("open boom")}, nil
return &fakeVideoSession{err: errVP8UnitOpenBoom}, nil
})
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-open-fails"}); err == nil || err.Error() != "open video track: open boom" {
if _, err := New(context.Background(), transport.Config{Carrier: "vp8channel-open-fails"}); err == nil || err.Error() != "open video track: open boom" { //nolint:lll // long test description
t.Fatalf("New() error = %v", err)
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestEpochHeaderTokenAndOutboundCapacity(t *testing.T) {
tr := &streamTransport{
stream: &fakeVideoStream{canSend: true},
@@ -256,6 +266,7 @@ func TestVP8FrameStateAssemblesAndRejectsCorruptFrames(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestHandleIncomingFrameEpochFilteringAndReconnect(t *testing.T) {
called := 0
tr := &streamTransport{
@@ -293,7 +304,10 @@ func TestHandleIncomingFrameEpochFilteringAndReconnect(t *testing.T) {
reconnected := false
tr.SetReconnectCallback(func() { reconnected = true })
stream := tr.stream.(*fakeVideoStream)
stream, ok := tr.stream.(*fakeVideoStream)
if !ok {
t.Fatalf("stream type = %T, want *fakeVideoStream", tr.stream)
}
if stream.reconnect == nil {
t.Fatal("SetReconnectCallback did not install stream callback")
}
@@ -304,6 +318,6 @@ func TestHandleIncomingFrameEpochFilteringAndReconnect(t *testing.T) {
reconnected = false
tr.handleIncomingFrame(mkFrame(tr.bindingToken, 2, []byte("after-restart")))
if !reconnected || tr.peerEpoch.Load() != 2 || tr.kcp == nil {
t.Fatalf("epoch change did not reset/reconnect: reconnected=%v epoch=%d kcp=%v", reconnected, tr.peerEpoch.Load(), tr.kcp)
t.Fatalf("epoch change did not reset/reconnect: reconnected=%v epoch=%d kcp=%v", reconnected, tr.peerEpoch.Load(), tr.kcp) //nolint:lll // long test description
}
}

View File

@@ -65,14 +65,14 @@ const (
)
var (
mu sync.Mutex
defaults mobileConfig
defaultsSet sync.Once
registerSet sync.Once
runClientWithReady = client.RunWithReady
cancel context.CancelFunc
done chan struct{}
ready chan struct{}
mu sync.Mutex //nolint:gochecknoglobals // package-level state intentional
defaults mobileConfig //nolint:gochecknoglobals // package-level state intentional
defaultsSet sync.Once //nolint:gochecknoglobals // package-level state intentional
registerSet sync.Once //nolint:gochecknoglobals // package-level state intentional
runClientWithReady = client.RunWithReady //nolint:gochecknoglobals // package-level state intentional
cancel context.CancelFunc //nolint:gochecknoglobals // package-level state intentional
done chan struct{} //nolint:gochecknoglobals // package-level state intentional
ready chan struct{} //nolint:gochecknoglobals // package-level state intentional
errRun error
)
@@ -616,6 +616,7 @@ func startWithConfig(
}
// WaitReady blocks until the selected transport is connected and the local SOCKS5 listener is ready.
//nolint:cyclop // straightforward state-machine waits with multiple terminal conditions
func WaitReady(timeoutMillis int) error {
mu.Lock()
r := ready

View File

@@ -48,7 +48,12 @@ func resetMobileGlobals(t *testing.T) {
logger.SetVerbose(false)
}
var clientRunWithReady = runClientWithReady
var clientRunWithReady = runClientWithReady //nolint:gochecknoglobals // package-level state intentional
var (
errMobileCheckFailed = errors.New("check failed")
errMobileRunFailed = errors.New("run failed")
)
func TestProtectorAndLogging(t *testing.T) {
resetMobileGlobals(t)
@@ -96,6 +101,7 @@ func TestDefaultsAndSetters(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestNormalizeBuildRoomAndClamp(t *testing.T) {
tests := map[string]string{
"datachannel": dataTransport,
@@ -133,28 +139,29 @@ func TestNormalizeBuildRoomAndClamp(t *testing.T) {
func TestStartValidation(t *testing.T) {
resetMobileGlobals(t)
if err := startWithConfig("", dataTransport, "room", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errCarrierRequired) {
if err := startWithConfig("", dataTransport, "room", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errCarrierRequired) { //nolint:lll // long test description
t.Fatalf("startWithConfig(missing carrier) = %v", err)
}
if err := startWithConfig("telemost", dataTransport, "", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errRoomIDRequired) {
if err := startWithConfig("telemost", dataTransport, "", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errRoomIDRequired) { //nolint:lll // long test description
t.Fatalf("startWithConfig(missing room) = %v", err)
}
if err := startWithConfig("jazz", dataTransport, "", "", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errClientIDRequired) {
if err := startWithConfig("jazz", dataTransport, "", "", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errClientIDRequired) { //nolint:lll // long test description
t.Fatalf("startWithConfig(missing client) = %v", err)
}
if err := startWithConfig("jazz", dataTransport, "", "client", "", 1080, "", "", mobileConfig{}); !errors.Is(err, errKeyHexRequired) {
if err := startWithConfig("jazz", dataTransport, "", "client", "", 1080, "", "", mobileConfig{}); !errors.Is(err, errKeyHexRequired) { //nolint:lll // long test description
t.Fatalf("startWithConfig(missing key) = %v", err)
}
mu.Lock()
cancel = func() {}
mu.Unlock()
if err := startWithConfig("jazz", dataTransport, "", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errAlreadyRunning) {
if err := startWithConfig("jazz", dataTransport, "", "client", "key", 1080, "", "", mobileConfig{}); !errors.Is(err, errAlreadyRunning) { //nolint:lll // long test description
t.Fatalf("startWithConfig(running) = %v", err)
}
resetMobileGlobals(t)
}
//nolint:cyclop // table-driven test naturally has many branches
func TestStartWithInjectedRunnerLifecycle(t *testing.T) {
resetMobileGlobals(t)
t.Cleanup(func() {
@@ -163,26 +170,26 @@ func TestStartWithInjectedRunnerLifecycle(t *testing.T) {
runClientWithReady = func(
ctx context.Context,
linkName, transportName, carrierName, roomURL, keyHex, clientID string,
linkName, transportName, carrierName, roomURL, _, clientID string,
localAddr string,
dnsServer, socksUser, socksPass string,
dnsServer, _, _ string,
onReady func(),
videoWidth int,
videoHeight int,
videoFPS int,
videoBitrate string,
videoHW string,
videoQRSize int,
videoQRRecovery string,
videoCodec string,
videoTileModule int,
videoTileRS int,
_ int,
_ int,
_ int,
_ string,
_ string,
_ int,
_ string,
_ string,
_ int,
_ int,
vp8FPS int,
vp8BatchSize int,
seiFPS int,
seiBatchSize int,
seiFragmentSize int,
seiAckTimeoutMS int,
_ int,
_ int,
_ int,
_ int,
) error {
if linkName != defaultLink || transportName != dataTransport || carrierName != carrierJazz ||
roomURL != "any" || clientID != "client" || localAddr != "127.0.0.1:1080" ||
@@ -210,6 +217,7 @@ func TestStartWithInjectedRunnerLifecycle(t *testing.T) {
}
}
//nolint:cyclop // table-driven test naturally has many branches
func TestStartUsesDefaultsAndCheckWithInjectedRunner(t *testing.T) {
resetMobileGlobals(t)
t.Cleanup(func() {
@@ -218,26 +226,26 @@ func TestStartUsesDefaultsAndCheckWithInjectedRunner(t *testing.T) {
runClientWithReady = func(
ctx context.Context,
linkName, transportName, carrierName, roomURL, keyHex, clientID string,
_, transportName, _, roomURL, _, _ string,
localAddr string,
dnsServer, socksUser, socksPass string,
_, socksUser, socksPass string,
onReady func(),
videoWidth int,
videoHeight int,
videoFPS int,
videoBitrate string,
videoHW string,
videoQRSize int,
videoQRRecovery string,
videoCodec string,
videoTileModule int,
videoTileRS int,
vp8FPS int,
vp8BatchSize int,
seiFPS int,
seiBatchSize int,
seiFragmentSize int,
seiAckTimeoutMS int,
_ int,
_ int,
_ int,
_ string,
_ string,
_ int,
_ string,
_ string,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
) error {
if transportName != defaultTransport || roomURL != "https://telemost.yandex.ru/j/room" ||
localAddr != "127.0.0.1:1081" || socksUser != "u" || socksPass != "p" {
@@ -259,26 +267,26 @@ func TestStartUsesDefaultsAndCheckWithInjectedRunner(t *testing.T) {
runClientWithReady = func(
ctx context.Context,
linkName, transportName, carrierName, roomURL, keyHex, clientID string,
localAddr string,
dnsServer, socksUser, socksPass string,
_, transportName, _, _, _, _ string,
_ string,
_, _, _ string,
onReady func(),
videoWidth int,
videoHeight int,
videoFPS int,
videoBitrate string,
videoHW string,
videoQRSize int,
videoQRRecovery string,
videoCodec string,
videoTileModule int,
videoTileRS int,
_ int,
_ int,
_ int,
_ string,
_ string,
_ int,
_ string,
_ string,
_ int,
_ int,
vp8FPS int,
vp8BatchSize int,
seiFPS int,
seiBatchSize int,
seiFragmentSize int,
seiAckTimeoutMS int,
_ int,
_ int,
_ int,
_ int,
) error {
if transportName != dataTransport || vp8FPS != 1 || vp8BatchSize != 64 {
t.Fatalf("Check args mismatch: transport=%q vp8=%d/%d", transportName, vp8FPS, vp8BatchSize)
@@ -304,35 +312,35 @@ func TestCheckTimeoutAndRunError(t *testing.T) {
runClientWithReady = func(
ctx context.Context,
linkName, transportName, carrierName, roomURL, keyHex, clientID string,
localAddr string,
dnsServer, socksUser, socksPass string,
onReady func(),
videoWidth int,
videoHeight int,
videoFPS int,
videoBitrate string,
videoHW string,
videoQRSize int,
videoQRRecovery string,
videoCodec string,
videoTileModule int,
videoTileRS int,
vp8FPS int,
vp8BatchSize int,
seiFPS int,
seiBatchSize int,
seiFragmentSize int,
seiAckTimeoutMS int,
_, _, _, _, _, _ string,
_ string,
_, _, _ string,
_ func(),
_ int,
_ int,
_ int,
_ string,
_ string,
_ int,
_ string,
_ string,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
_ int,
) error {
<-ctx.Done()
return nil
}
if _, err := Check("telemost", defaultTransport, "room", "client", "key", 1083, 1, 30, 1); !errors.Is(err, errStartTimedOut) {
if _, err := Check("telemost", defaultTransport, "room", "client", "key", 1083, 1, 30, 1); !errors.Is(err, errStartTimedOut) { //nolint:lll // long test description
t.Fatalf("Check(timeout) error = %v, want %v", err, errStartTimedOut)
}
want := errors.New("check failed")
want := errMobileCheckFailed
runClientWithReady = func(
context.Context,
string, string, string, string, string, string,
@@ -369,7 +377,7 @@ func TestWaitReadyStatesAndStop(t *testing.T) {
}
mu.Lock()
errRun = errors.New("run failed")
errRun = errMobileRunFailed
mu.Unlock()
if err := WaitReady(1); err == nil || err.Error() != "run failed" {
t.Fatalf("WaitReady(run err) = %v", err)