mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-05-26 07:08:11 +00:00
feat: add support for reading configuration from YAML file
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
// Package main provides the olcrtc CLI entrypoint.
|
||||
//
|
||||
// Usage: olcrtc <config.yaml>
|
||||
//
|
||||
// All runtime settings come from the YAML file. There are no other CLI flags.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -26,8 +29,11 @@ import (
|
||||
|
||||
const modeGen = "gen"
|
||||
|
||||
// ErrDataDirRequired is returned when no data directory is specified.
|
||||
var ErrDataDirRequired = errors.New("data directory required (use -data data)")
|
||||
// ErrConfigPathRequired is returned when no config file is provided.
|
||||
var ErrConfigPathRequired = errors.New("usage: olcrtc <config.yaml>")
|
||||
|
||||
// ErrDataDirRequired is returned when the YAML config does not specify a data directory.
|
||||
var ErrDataDirRequired = errors.New("data directory required (set 'data:' in YAML)")
|
||||
|
||||
//nolint:gochecknoglobals // Tests replace the long-running session runner with a bounded function.
|
||||
var runSession = session.Run
|
||||
@@ -35,45 +41,12 @@ var runSession = session.Run
|
||||
//nolint:gochecknoglobals // Tests replace gen runner with a stub.
|
||||
var runGen = execGen
|
||||
|
||||
type config struct {
|
||||
configPath string
|
||||
mode string
|
||||
link string
|
||||
transport string
|
||||
auth string
|
||||
engine string
|
||||
url string
|
||||
token string
|
||||
roomID string
|
||||
clientID string
|
||||
socksPort int
|
||||
socksHost string
|
||||
socksUser string
|
||||
socksPass string
|
||||
keyHex string
|
||||
debug bool
|
||||
dataDir string
|
||||
dnsServer string
|
||||
socksProxyAddr string
|
||||
socksProxyPort int
|
||||
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
|
||||
amount int
|
||||
ffmpegPath string
|
||||
// loadedConfig bundles the parsed YAML file and the derived session config.
|
||||
type loadedConfig struct {
|
||||
scfg session.Config
|
||||
dataDir string
|
||||
debug bool
|
||||
ffmpegPath string
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -90,76 +63,54 @@ func run() error {
|
||||
func runWithArgs(args []string) error {
|
||||
session.RegisterDefaults()
|
||||
|
||||
cfg, err := parseFlagsFrom(args, flag.ExitOnError)
|
||||
if len(args) != 1 || args[0] == "-h" || args[0] == "--help" || args[0] == "-help" {
|
||||
return ErrConfigPathRequired
|
||||
}
|
||||
|
||||
cfg, err := loadConfig(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runWithConfig(cfg)
|
||||
}
|
||||
|
||||
// applyConfigFile loads cfg.configPath (if set) and merges its values into scfg.
|
||||
// CLI flags (already populated) take precedence over YAML.
|
||||
func applyConfigFile(cfg config, scfg session.Config) (session.Config, error) {
|
||||
if cfg.configPath == "" {
|
||||
return scfg, nil
|
||||
}
|
||||
f, err := configpkg.Load(cfg.configPath)
|
||||
func loadConfig(path string) (loadedConfig, error) {
|
||||
f, err := configpkg.Load(path)
|
||||
if err != nil {
|
||||
return scfg, fmt.Errorf("load config: %w", err)
|
||||
return loadedConfig{}, fmt.Errorf("load config: %w", err)
|
||||
}
|
||||
return configpkg.Apply(scfg, f), nil
|
||||
return loadedConfig{
|
||||
scfg: configpkg.Apply(session.Config{}, f),
|
||||
dataDir: f.Data,
|
||||
debug: f.Debug,
|
||||
ffmpegPath: f.FFmpeg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// mergeFileMeta fills cmd-level fields (data dir, debug, ffmpeg) that aren't
|
||||
// part of session.Config but still need to come from the YAML file.
|
||||
func mergeFileMeta(cfg *config, f configpkg.File) {
|
||||
if cfg.dataDir == "" {
|
||||
cfg.dataDir = f.Data
|
||||
}
|
||||
if !cfg.debug {
|
||||
cfg.debug = f.Debug
|
||||
}
|
||||
if (cfg.ffmpegPath == "" || cfg.ffmpegPath == "ffmpeg") && f.FFmpeg != "" {
|
||||
cfg.ffmpegPath = f.FFmpeg
|
||||
}
|
||||
}
|
||||
|
||||
func runWithConfig(cfg config) error {
|
||||
if cfg.configPath != "" {
|
||||
f, err := configpkg.Load(cfg.configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("load config: %w", err)
|
||||
}
|
||||
mergeFileMeta(&cfg, f)
|
||||
}
|
||||
|
||||
func runWithConfig(cfg loadedConfig) error {
|
||||
configureLogging(cfg.debug)
|
||||
|
||||
if cfg.ffmpegPath != "ffmpeg" && cfg.ffmpegPath != "" {
|
||||
videochannel.FFmpegPath = cfg.ffmpegPath
|
||||
}
|
||||
|
||||
if cfg.mode == modeGen {
|
||||
return runGen(cfg)
|
||||
}
|
||||
|
||||
return runSessionMode(cfg)
|
||||
}
|
||||
|
||||
func runSessionMode(cfg config) error {
|
||||
scfg, err := applyConfigFile(cfg, toSessionConfig(cfg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scfg, err = session.ApplyAuthDefaults(scfg)
|
||||
scfg, err := session.ApplyAuthDefaults(cfg.scfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate config: %w", err)
|
||||
}
|
||||
|
||||
if scfg.Mode == modeGen {
|
||||
return runGen(scfg)
|
||||
}
|
||||
|
||||
return runSessionMode(cfg.dataDir, scfg)
|
||||
}
|
||||
|
||||
func runSessionMode(dataDir string, scfg session.Config) error {
|
||||
if err := session.Validate(scfg); err != nil {
|
||||
return fmt.Errorf("validate config: %w", err)
|
||||
}
|
||||
|
||||
dataDir := cfg.dataDir
|
||||
if dataDir == "" {
|
||||
return ErrDataDirRequired
|
||||
}
|
||||
@@ -194,15 +145,7 @@ func runSessionMode(cfg config) error {
|
||||
}
|
||||
}
|
||||
|
||||
func execGen(cfg config) error {
|
||||
scfg, err := applyConfigFile(cfg, toSessionConfig(cfg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scfg, err = session.ApplyAuthDefaults(scfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validate gen config: %w", err)
|
||||
}
|
||||
func execGen(scfg session.Config) error {
|
||||
if err := session.ValidateGen(scfg); err != nil {
|
||||
return fmt.Errorf("validate gen config: %w", err)
|
||||
}
|
||||
@@ -227,62 +170,6 @@ func execGen(cfg config) error {
|
||||
}
|
||||
}
|
||||
|
||||
func parseFlagsFrom(args []string, errorHandling flag.ErrorHandling) (config, error) {
|
||||
cfg := config{}
|
||||
fs := flag.NewFlagSet("olcrtc", errorHandling)
|
||||
if errorHandling == flag.ContinueOnError {
|
||||
fs.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
fs.StringVar(&cfg.configPath, "config", "", "Path to YAML config file (CLI flags override file values)")
|
||||
fs.StringVar(&cfg.mode, "mode", "", "Mode: srv or cnc")
|
||||
fs.StringVar(&cfg.link, "link", "", "Link: direct (p2p connection type)")
|
||||
fs.StringVar(&cfg.transport, "transport", "", "Transport: datachannel, videochannel, seichannel")
|
||||
fs.StringVar(&cfg.auth, "auth", "", "Auth provider: telemost, jazz, wbstream, none")
|
||||
fs.StringVar(&cfg.engine, "engine", "", "Engine (required when -auth none): livekit, goolom, salutejazz")
|
||||
fs.StringVar(&cfg.url, "url", "", "SFU WebSocket URL (required when -auth none)")
|
||||
fs.StringVar(&cfg.token, "token", "", "Access token (required when -auth none)")
|
||||
fs.StringVar(&cfg.roomID, "id", "", "Room ID")
|
||||
fs.StringVar(&cfg.clientID, "client-id", "", "Client ID: binds one srv to one cnc (required)")
|
||||
fs.IntVar(&cfg.socksPort, "socks-port", 0, "SOCKS5 port (client only)")
|
||||
fs.StringVar(&cfg.socksHost, "socks-host", "", "SOCKS5 listen host (client only)")
|
||||
fs.StringVar(&cfg.socksUser, "socks-user", "", "SOCKS5 username for incoming connections (client only, optional)")
|
||||
fs.StringVar(&cfg.socksPass, "socks-pass", "", "SOCKS5 password for incoming connections (client only, optional)")
|
||||
fs.StringVar(&cfg.keyHex, "key", "", "Shared encryption key (hex)")
|
||||
fs.BoolVar(&cfg.debug, "debug", false, "Enable verbose logging")
|
||||
fs.StringVar(&cfg.dataDir, "data", "", "Path to data directory")
|
||||
fs.StringVar(&cfg.dnsServer, "dns", "", "DNS server (e.g. 1.1.1.1:53)")
|
||||
fs.StringVar(&cfg.socksProxyAddr, "socks-proxy", "", "SOCKS5 proxy address (server only)")
|
||||
fs.IntVar(&cfg.socksProxyPort, "socks-proxy-port", 0, "SOCKS5 proxy port (server only)")
|
||||
fs.IntVar(&cfg.videoWidth, "video-w", 0, "Video logical width (videochannel only)")
|
||||
fs.IntVar(&cfg.videoHeight, "video-h", 0, "Video logical height (videochannel only)")
|
||||
fs.IntVar(&cfg.videoFPS, "video-fps", 0, "Video frames per second (videochannel only)")
|
||||
fs.StringVar(&cfg.videoBitrate, "video-bitrate", "", "Video bitrate (videochannel only)")
|
||||
fs.StringVar(&cfg.videoHW, "video-hw", "", "Hardware acceleration (none, nvenc)")
|
||||
fs.IntVar(&cfg.videoQRSize, "video-qr-size", 0, "Video QR code fragment size (videochannel only)")
|
||||
fs.StringVar(&cfg.videoQRRecovery, "video-qr-recovery", "low",
|
||||
"QR error correction: low (7%), medium (15%), high (25%), highest (30%)")
|
||||
fs.StringVar(&cfg.videoCodec, "video-codec", "qrcode", "Visual codec: qrcode or tile")
|
||||
fs.IntVar(&cfg.videoTileModule, "video-tile-module", 0,
|
||||
"Tile module size in pixels 1..270 (videochannel tile only, default 4)")
|
||||
fs.IntVar(&cfg.videoTileRS, "video-tile-rs", 0,
|
||||
"Tile Reed-Solomon parity percent 0..200 (videochannel tile only, default 20)")
|
||||
fs.IntVar(&cfg.vp8FPS, "vp8-fps", 0, "VP8 frames per second (vp8channel only, default 25)")
|
||||
fs.IntVar(&cfg.vp8BatchSize, "vp8-batch", 0, "VP8 frames per tick (vp8channel only, default 1)")
|
||||
fs.IntVar(&cfg.seiFPS, "fps", 0, "Frames per second for transports that use video timing (seichannel)")
|
||||
fs.IntVar(&cfg.seiBatchSize, "batch", 0, "Transport frames per tick for batched transports (seichannel)")
|
||||
fs.IntVar(&cfg.seiFragmentSize, "frag", 0, "Fragment size in bytes for fragmented transports (seichannel)")
|
||||
fs.IntVar(&cfg.seiAckTimeoutMS, "ack-ms", 0, "ACK timeout in milliseconds for reliable visual transports (seichannel)")
|
||||
fs.IntVar(&cfg.amount, "amount", 0, "Number of rooms to generate (gen mode only)")
|
||||
fs.StringVar(&cfg.ffmpegPath, "ffmpeg", "ffmpeg", "Path to ffmpeg executable")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return cfg, fmt.Errorf("parse flags: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// noisyPrefixes lists log prefixes from third-party libs that spam via std log.
|
||||
var noisyPrefixes = [][]byte{ //nolint:gochecknoglobals // package-level filter list
|
||||
[]byte("turnc"), []byte("[turn]"), []byte("Fail to refresh permissions"),
|
||||
@@ -309,10 +196,8 @@ func configureLogging(debug bool) {
|
||||
logger.SetVerbose(true)
|
||||
return
|
||||
}
|
||||
// Suppress noisy LiveKit/pion logs unless debug is enabled.
|
||||
_ = os.Setenv("PION_LOG_DISABLE", "all")
|
||||
lksdk.SetLogger(protoLogger.GetDiscardLogger())
|
||||
// turnc logs via std log directly — filter it out.
|
||||
log.SetOutput(filteredWriter{w: os.Stderr})
|
||||
}
|
||||
|
||||
@@ -339,45 +224,6 @@ func loadNames(dataDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func toSessionConfig(cfg config) session.Config {
|
||||
return session.Config{
|
||||
Mode: cfg.mode,
|
||||
Link: cfg.link,
|
||||
Transport: cfg.transport,
|
||||
Auth: cfg.auth,
|
||||
Engine: cfg.engine,
|
||||
URL: cfg.url,
|
||||
Token: cfg.token,
|
||||
RoomID: cfg.roomID,
|
||||
ClientID: cfg.clientID,
|
||||
KeyHex: cfg.keyHex,
|
||||
SOCKSHost: cfg.socksHost,
|
||||
SOCKSPort: cfg.socksPort,
|
||||
SOCKSUser: cfg.socksUser,
|
||||
SOCKSPass: cfg.socksPass,
|
||||
DNSServer: cfg.dnsServer,
|
||||
SOCKSProxyAddr: cfg.socksProxyAddr,
|
||||
SOCKSProxyPort: cfg.socksProxyPort,
|
||||
VideoWidth: cfg.videoWidth,
|
||||
VideoHeight: cfg.videoHeight,
|
||||
VideoFPS: cfg.videoFPS,
|
||||
VideoBitrate: cfg.videoBitrate,
|
||||
VideoHW: cfg.videoHW,
|
||||
VideoQRSize: cfg.videoQRSize,
|
||||
VideoQRRecovery: cfg.videoQRRecovery,
|
||||
VideoCodec: cfg.videoCodec,
|
||||
VideoTileModule: cfg.videoTileModule,
|
||||
VideoTileRS: cfg.videoTileRS,
|
||||
VP8FPS: cfg.vp8FPS,
|
||||
VP8BatchSize: cfg.vp8BatchSize,
|
||||
SEIFPS: cfg.seiFPS,
|
||||
SEIBatchSize: cfg.seiBatchSize,
|
||||
SEIFragmentSize: cfg.seiFragmentSize,
|
||||
SEIAckTimeoutMS: cfg.seiAckTimeoutMS,
|
||||
Amount: cfg.amount,
|
||||
}
|
||||
}
|
||||
|
||||
func waitForShutdown(errCh <-chan error) error {
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -14,110 +13,40 @@ import (
|
||||
|
||||
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", //nolint:goconst // test literal, repetition is intentional
|
||||
transport: "vp8channel",
|
||||
auth: "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", //nolint:goconst // test literal, repetition is intentional
|
||||
socksProxyAddr: "proxy",
|
||||
socksProxyPort: 1081,
|
||||
videoWidth: 640,
|
||||
videoHeight: 480,
|
||||
videoFPS: 30,
|
||||
videoBitrate: "1M",
|
||||
videoHW: "none",
|
||||
videoQRSize: 4,
|
||||
videoQRRecovery: "low",
|
||||
videoCodec: "qrcode",
|
||||
videoTileModule: 4,
|
||||
videoTileRS: 20,
|
||||
vp8FPS: 25,
|
||||
vp8BatchSize: 8,
|
||||
seiFPS: 40,
|
||||
seiBatchSize: 3,
|
||||
seiFragmentSize: 512,
|
||||
seiAckTimeoutMS: 1500,
|
||||
amount: 5,
|
||||
}
|
||||
|
||||
got := toSessionConfig(cfg)
|
||||
if got.Mode != cfg.mode || got.Auth != "jazz" || got.SOCKSPort != cfg.socksPort ||
|
||||
got.VideoTileRS != cfg.videoTileRS || got.VP8BatchSize != cfg.vp8BatchSize ||
|
||||
got.SEIFPS != cfg.seiFPS || got.SEIBatchSize != cfg.seiBatchSize ||
|
||||
got.SEIFragmentSize != cfg.seiFragmentSize || got.SEIAckTimeoutMS != cfg.seiAckTimeoutMS ||
|
||||
got.Amount != cfg.amount {
|
||||
t.Fatalf("toSessionConfig() = %+v", got)
|
||||
func writeYAML(t *testing.T, body string) string {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "olcrtc.yaml")
|
||||
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
||||
t.Fatalf("write yaml: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
//nolint:cyclop // table-driven test naturally has many branches
|
||||
func TestParseFlagsFrom(t *testing.T) {
|
||||
cfg, err := parseFlagsFrom([]string{
|
||||
"-mode", "srv", //nolint:goconst // test literal, repetition is intentional
|
||||
"-link", "direct",
|
||||
"-transport", "vp8channel",
|
||||
"-auth", "telemost",
|
||||
"-id", "room",
|
||||
"-client-id", "client",
|
||||
"-socks-port", "1080",
|
||||
"-socks-host", "127.0.0.1",
|
||||
"-key", "key",
|
||||
"-debug",
|
||||
"-data", "data",
|
||||
"-dns", "9.9.9.9:53",
|
||||
"-socks-proxy", "proxy",
|
||||
"-socks-proxy-port", "1081",
|
||||
"-video-w", "640",
|
||||
"-video-h", "480",
|
||||
"-video-fps", "30",
|
||||
"-video-bitrate", "1M",
|
||||
"-video-hw", "none",
|
||||
"-video-qr-size", "128",
|
||||
"-video-qr-recovery", "high",
|
||||
"-video-codec", "tile",
|
||||
"-video-tile-module", "6",
|
||||
"-video-tile-rs", "40",
|
||||
"-vp8-fps", "24",
|
||||
"-vp8-batch", "3",
|
||||
"-fps", "40",
|
||||
"-batch", "4",
|
||||
"-frag", "512",
|
||||
"-ack-ms", "1500",
|
||||
"-amount", "7",
|
||||
}, flag.ContinueOnError)
|
||||
if err != nil {
|
||||
t.Fatalf("parseFlagsFrom() error = %v", err)
|
||||
func TestRunWithArgsRequiresConfig(t *testing.T) {
|
||||
session.RegisterDefaults()
|
||||
if err := runWithArgs(nil); !errors.Is(err, ErrConfigPathRequired) {
|
||||
t.Fatalf("runWithArgs(nil) = %v, want %v", err, ErrConfigPathRequired)
|
||||
}
|
||||
if cfg.mode != "srv" || cfg.auth != "telemost" || cfg.roomID != "room" ||
|
||||
cfg.debug != true || cfg.videoCodec != "tile" || cfg.videoTileRS != 40 ||
|
||||
cfg.vp8FPS != 24 || cfg.vp8BatchSize != 3 || cfg.seiFPS != 40 ||
|
||||
cfg.seiBatchSize != 4 || cfg.seiFragmentSize != 512 || cfg.seiAckTimeoutMS != 1500 ||
|
||||
cfg.amount != 7 {
|
||||
t.Fatalf("parseFlagsFrom() = %+v", cfg)
|
||||
if err := runWithArgs([]string{"-h"}); !errors.Is(err, ErrConfigPathRequired) {
|
||||
t.Fatalf("runWithArgs(-h) = %v, want %v", err, ErrConfigPathRequired)
|
||||
}
|
||||
|
||||
_, err = parseFlagsFrom([]string{"-bad"}, flag.ContinueOnError)
|
||||
if err == nil {
|
||||
t.Fatal("parseFlagsFrom(bad flag) error = nil")
|
||||
if err := runWithArgs([]string{"a.yaml", "b.yaml"}); !errors.Is(err, ErrConfigPathRequired) {
|
||||
t.Fatalf("runWithArgs(two args) = %v, want %v", err, ErrConfigPathRequired)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunGenModeValidationErrors(t *testing.T) {
|
||||
session.RegisterDefaults()
|
||||
|
||||
if err := runWithConfig(config{mode: "gen"}); err == nil { //nolint:goconst // test literal, repetition is intentional
|
||||
if err := runWithConfig(loadedConfig{scfg: session.Config{Mode: "gen"}}); err == nil {
|
||||
t.Fatal("runWithConfig(gen, no carrier) error = nil")
|
||||
}
|
||||
|
||||
if err := runWithConfig(config{mode: "gen", auth: "wbstream", dnsServer: "1.1.1.1:53"}); err == nil { //nolint:goconst,lll // test literal, repetition is intentional
|
||||
cfg := loadedConfig{scfg: session.Config{
|
||||
Mode: "gen", Auth: "wbstream", DNSServer: "1.1.1.1:53",
|
||||
}}
|
||||
if err := runWithConfig(cfg); err == nil {
|
||||
t.Fatal("runWithConfig(gen, amount=0) error = nil")
|
||||
}
|
||||
}
|
||||
@@ -128,16 +57,18 @@ func TestRunGenModeCallsGen(t *testing.T) {
|
||||
var collected []string
|
||||
oldRunGen := runGen
|
||||
t.Cleanup(func() { runGen = oldRunGen })
|
||||
runGen = func(cfg config) error {
|
||||
if cfg.auth != "wbstream" || cfg.dnsServer != "1.1.1.1:53" || cfg.amount != 3 {
|
||||
t.Fatalf("runGen cfg = %+v", cfg)
|
||||
runGen = func(scfg session.Config) error {
|
||||
if scfg.Auth != "wbstream" || scfg.DNSServer != "1.1.1.1:53" || scfg.Amount != 3 {
|
||||
t.Fatalf("runGen scfg = %+v", scfg)
|
||||
}
|
||||
collected = append(collected, "ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := runWithConfig(config{mode: "gen", auth: "wbstream", dnsServer: "1.1.1.1:53", amount: 3})
|
||||
if err != nil {
|
||||
cfg := loadedConfig{scfg: session.Config{
|
||||
Mode: "gen", Auth: "wbstream", DNSServer: "1.1.1.1:53", Amount: 3,
|
||||
}}
|
||||
if err := runWithConfig(cfg); err != nil {
|
||||
t.Fatalf("runWithConfig(gen) error = %v", err)
|
||||
}
|
||||
if len(collected) != 1 {
|
||||
@@ -147,22 +78,21 @@ func TestRunGenModeCallsGen(t *testing.T) {
|
||||
|
||||
func TestRunWithConfigValidationAndDataDirErrors(t *testing.T) {
|
||||
session.RegisterDefaults()
|
||||
cfg := config{
|
||||
mode: "srv",
|
||||
link: "direct",
|
||||
transport: "datachannel",
|
||||
auth: "jazz",
|
||||
clientID: "client",
|
||||
keyHex: "key",
|
||||
dnsServer: "1.1.1.1:53",
|
||||
videoCodec: "qrcode",
|
||||
scfg := session.Config{
|
||||
Mode: "srv",
|
||||
Link: "direct",
|
||||
Transport: "datachannel",
|
||||
Auth: "jazz",
|
||||
ClientID: "client",
|
||||
KeyHex: "key",
|
||||
DNSServer: "1.1.1.1:53",
|
||||
}
|
||||
if err := runWithConfig(cfg); !errors.Is(err, ErrDataDirRequired) {
|
||||
if err := runWithConfig(loadedConfig{scfg: scfg}); !errors.Is(err, ErrDataDirRequired) {
|
||||
t.Fatalf("runWithConfig(no data dir) = %v, want %v", err, ErrDataDirRequired)
|
||||
}
|
||||
|
||||
cfg.mode = ""
|
||||
if err := runWithConfig(cfg); err == nil {
|
||||
scfg.Mode = ""
|
||||
if err := runWithConfig(loadedConfig{scfg: scfg}); err == nil {
|
||||
t.Fatal("runWithConfig(invalid config) error = nil")
|
||||
}
|
||||
}
|
||||
@@ -194,17 +124,22 @@ func TestRunWithArgsSuccessfulSessionReturn(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := runWithArgs([]string{
|
||||
"-mode", "srv",
|
||||
"-link", "direct",
|
||||
"-transport", "datachannel",
|
||||
"-auth", "jazz",
|
||||
"-client-id", "client",
|
||||
"-key", "key",
|
||||
"-dns", "1.1.1.1:53",
|
||||
"-data", dir,
|
||||
})
|
||||
if err != nil {
|
||||
yamlPath := writeYAML(t, `
|
||||
mode: srv
|
||||
link: direct
|
||||
auth:
|
||||
provider: jazz
|
||||
room:
|
||||
client_id: client
|
||||
crypto:
|
||||
key: key
|
||||
net:
|
||||
transport: datachannel
|
||||
dns: 1.1.1.1:53
|
||||
data: `+dir+`
|
||||
`)
|
||||
|
||||
if err := runWithArgs([]string{yamlPath}); err != nil {
|
||||
t.Fatalf("runWithArgs() error = %v", err)
|
||||
}
|
||||
if !called {
|
||||
|
||||
Reference in New Issue
Block a user