mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-05-26 07:08:11 +00:00
fix: golangci errors
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"},
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user