From cd11a6720fa1661d5b8e6212960a7979b6d51516 Mon Sep 17 00:00:00 2001 From: Winlin Date: Sat, 18 Apr 2026 20:33:07 -0400 Subject: [PATCH] Proxy: Harden internal/env tests and add counterfeiter fakes. v7.0.144 (#4665) - **Refactor `internal/env` for testability.** Route every `os`/filesystem call in `env.go` through swappable package-level function variables (`getEnv`, `setEnv`, `lookupEnv`, `openFile`). Split `parseEnvFile` into a thin file-opening wrapper plus a pure `parseEnvReader(io.Reader)` so the parser can be tested directly without touching disk. - **Hermetic tests, 96.9% coverage.** Rewrite `internal/env/env_test.go` to install in-memory fakes via `withFakeEnv` / `withFakeOpen` helpers that swap the package vars and restore them on `t.Cleanup`. Tests no longer mutate real process env or write temp `.env` files, removing a source of flakiness under parallel test execution. New cases cover `NewEnvironment`, `setEnvDefault`, `loadEnvFile` error paths, and edge cases in the parser. - **Counterfeiter-based fake generation.** Add `counterfeiter` as a Go tool dependency, a `//go:generate` directive for the `Environment` interface (`internal/env/gen.go`), and commit the generated `internal/env/envfakes/fake_environment.go` so downstream packages can test against a spec-faithful fake instead of hand-rolling stubs. Expose the step as `make generate`. - **Tooling.** `scripts/proxy-utest.sh` gains a `--coverage` / `-c` flag that runs `go test -coverprofile=...` across `./cmd/...` and `./internal/...` and prints per-function coverage via `go tool cover -func`. The `srs-develop` skill doc is updated to include the regenerate-fakes step and the new coverage flag. - **Go version.** Bump `go.mod` to Go 1.25 (required for the `go tool` directive used to pin the counterfeiter CLI as a tool dep). --------- Co-authored-by: Claude Opus 4.7 --- .openclaw/skills/srs-develop/SKILL.md | 12 +- .../skills/srs-develop/scripts/proxy-utest.sh | 40 +- Makefile | 5 +- go.mod | 9 +- go.sum | 12 + internal/env/env.go | 103 +- internal/env/env_test.go | 321 +++- internal/env/envfakes/fake_environment.go | 1422 +++++++++++++++++ internal/env/gen.go | 6 + internal/version/version.go | 2 +- trunk/doc/CHANGELOG.md | 1 + trunk/src/core/srs_core_version7.hpp | 2 +- 12 files changed, 1796 insertions(+), 139 deletions(-) create mode 100644 internal/env/envfakes/fake_environment.go create mode 100644 internal/env/gen.go diff --git a/.openclaw/skills/srs-develop/SKILL.md b/.openclaw/skills/srs-develop/SKILL.md index 3b8bac662..d6c840d39 100644 --- a/.openclaw/skills/srs-develop/SKILL.md +++ b/.openclaw/skills/srs-develop/SKILL.md @@ -105,15 +105,19 @@ Only after the user confirms the routing do you proceed to Step 2. **Step 3: Implement and Verify** 1. Implement the code change. -2. Run the proxy unit tests to verify: +2. If you changed or added a Go interface with a `//go:generate go tool counterfeiter ...` directive, regenerate fakes: ``` - bash scripts/proxy-utest.sh + make generate ``` -3. Run the proxy E2E test (starts proxy + SRS origin, publishes RTMP, verifies playback): +3. Run the proxy unit tests to verify: + ``` + bash scripts/proxy-utest.sh --coverage + ``` +4. Run the proxy E2E test (starts proxy + SRS origin, publishes RTMP, verifies playback): ``` bash scripts/proxy-e2e-test.sh ``` -4. If any tests fail, fix the issues and re-run until all tests pass. +5. If any tests fail, fix the issues and re-run until all tests pass. All script paths are relative to this skill's directory. diff --git a/.openclaw/skills/srs-develop/scripts/proxy-utest.sh b/.openclaw/skills/srs-develop/scripts/proxy-utest.sh index 0327e861e..9e030d99f 100755 --- a/.openclaw/skills/srs-develop/scripts/proxy-utest.sh +++ b/.openclaw/skills/srs-develop/scripts/proxy-utest.sh @@ -2,6 +2,30 @@ # Run unit tests for the proxy server (cmd/ and internal/ packages). set -e +usage() { + cat <<'EOF' +Run unit tests for the proxy server (cmd/ and internal/ packages). + +Usage: + proxy-utest.sh # run tests + proxy-utest.sh --coverage # run tests and print per-function coverage + proxy-utest.sh -c # short form of --coverage +EOF +} + +COVERAGE=0 +for arg in "$@"; do + case "$arg" in + -c|--coverage) COVERAGE=1 ;; + -h|--help) usage; exit 0 ;; + *) + echo "Error: unknown argument: $arg" >&2 + usage >&2 + exit 2 + ;; + esac +done + SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd)" # Navigate: scripts/ -> srs-develop/ -> skills/ -> .openclaw/ -> srs WORKSPACE="$(cd -P "$SCRIPT_DIR/../../../.." && pwd)" @@ -12,6 +36,18 @@ if [[ ! -f "$WORKSPACE/go.mod" ]]; then fi cd "$WORKSPACE" -echo "Running proxy unit tests in: $WORKSPACE" -go test ./cmd/... ./internal/... -v +PACKAGES=(./cmd/... ./internal/...) + +if [[ $COVERAGE -eq 1 ]]; then + COVER_FILE="$(mktemp -t proxy-utest-coverage.XXXXXX.out)" + trap 'rm -f "$COVER_FILE"' EXIT + echo "Running proxy unit tests with coverage in: $WORKSPACE" + go test "${PACKAGES[@]}" -v -coverprofile="$COVER_FILE" -coverpkg=./cmd/...,./internal/... + echo + echo "=== Coverage (per function) ===" + go tool cover -func="$COVER_FILE" +else + echo "Running proxy unit tests in: $WORKSPACE" + go test "${PACKAGES[@]}" -v +fi diff --git a/Makefile b/Makefile index 8921a5619..682f450f5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ -.PHONY: all build test fmt clean run +.PHONY: all build test fmt clean run generate all: build build: fmt bin/srs-proxy +generate: + go generate ./... + bin/srs-proxy: cmd/proxy/*.go internal/**/*.go @mkdir -p bin go build -o bin/srs-proxy ./cmd/proxy diff --git a/go.mod b/go.mod index 709a04b48..cf20fa059 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,17 @@ module srsx -go 1.24 +go 1.25.0 require github.com/go-redis/redis/v8 v8.11.5 require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 // indirect + golang.org/x/mod v0.34.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/text v0.35.0 // indirect + golang.org/x/tools v0.43.0 // indirect ) + +tool github.com/maxbrunsfeld/counterfeiter/v6 diff --git a/go.sum b/go.sum index 17906ec30..372f6a0fd 100644 --- a/go.sum +++ b/go.sum @@ -6,18 +6,30 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2 h1:V23nK2R2B63g2GhygF9zVGpnigmhvoZoH8d0hrZwMGY= +github.com/maxbrunsfeld/counterfeiter/v6 v6.12.2/go.mod h1:Mr897yU9FmyKaQDPtRlVKibrjz40XXyOHUfyZBPSyZU= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/env/env.go b/internal/env/env.go index b0afd2d2e..a71b411b8 100644 --- a/internal/env/env.go +++ b/internal/env/env.go @@ -6,6 +6,7 @@ package env import ( "bufio" "context" + "io" "os" "strings" @@ -13,6 +14,17 @@ import ( "srsx/internal/logger" ) +// Indirections over os and filesystem primitives so tests can swap them +// without touching real process env or the filesystem. +var ( + getEnv = os.Getenv + setEnv = os.Setenv + lookupEnv = os.LookupEnv + openFile = func(name string) (io.ReadCloser, error) { + return os.Open(name) + } +) + // Environment provides access to environment variables. type Environment interface { // Go pprof profiling @@ -73,91 +85,91 @@ func NewEnvironment(ctx context.Context) (Environment, error) { } func (e *environment) GoPprof() string { - return os.Getenv("GO_PPROF") + return getEnv("GO_PPROF") } func (e *environment) GraceQuitTimeout() string { - return os.Getenv("PROXY_GRACE_QUIT_TIMEOUT") + return getEnv("PROXY_GRACE_QUIT_TIMEOUT") } func (e *environment) ForceQuitTimeout() string { - return os.Getenv("PROXY_FORCE_QUIT_TIMEOUT") + return getEnv("PROXY_FORCE_QUIT_TIMEOUT") } func (e *environment) HttpAPI() string { - return os.Getenv("PROXY_HTTP_API") + return getEnv("PROXY_HTTP_API") } func (e *environment) HttpServer() string { - return os.Getenv("PROXY_HTTP_SERVER") + return getEnv("PROXY_HTTP_SERVER") } func (e *environment) RtmpServer() string { - return os.Getenv("PROXY_RTMP_SERVER") + return getEnv("PROXY_RTMP_SERVER") } func (e *environment) WebRTCServer() string { - return os.Getenv("PROXY_WEBRTC_SERVER") + return getEnv("PROXY_WEBRTC_SERVER") } func (e *environment) SRTServer() string { - return os.Getenv("PROXY_SRT_SERVER") + return getEnv("PROXY_SRT_SERVER") } func (e *environment) SystemAPI() string { - return os.Getenv("PROXY_SYSTEM_API") + return getEnv("PROXY_SYSTEM_API") } func (e *environment) StaticFiles() string { - return os.Getenv("PROXY_STATIC_FILES") + return getEnv("PROXY_STATIC_FILES") } func (e *environment) LoadBalancerType() string { - return os.Getenv("PROXY_LOAD_BALANCER_TYPE") + return getEnv("PROXY_LOAD_BALANCER_TYPE") } func (e *environment) RedisHost() string { - return os.Getenv("PROXY_REDIS_HOST") + return getEnv("PROXY_REDIS_HOST") } func (e *environment) RedisPort() string { - return os.Getenv("PROXY_REDIS_PORT") + return getEnv("PROXY_REDIS_PORT") } func (e *environment) RedisPassword() string { - return os.Getenv("PROXY_REDIS_PASSWORD") + return getEnv("PROXY_REDIS_PASSWORD") } func (e *environment) RedisDB() string { - return os.Getenv("PROXY_REDIS_DB") + return getEnv("PROXY_REDIS_DB") } func (e *environment) DefaultBackendEnabled() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_ENABLED") + return getEnv("PROXY_DEFAULT_BACKEND_ENABLED") } func (e *environment) DefaultBackendIP() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_IP") + return getEnv("PROXY_DEFAULT_BACKEND_IP") } func (e *environment) DefaultBackendRTMP() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_RTMP") + return getEnv("PROXY_DEFAULT_BACKEND_RTMP") } func (e *environment) DefaultBackendHttp() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_HTTP") + return getEnv("PROXY_DEFAULT_BACKEND_HTTP") } func (e *environment) DefaultBackendAPI() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_API") + return getEnv("PROXY_DEFAULT_BACKEND_API") } func (e *environment) DefaultBackendRTC() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_RTC") + return getEnv("PROXY_DEFAULT_BACKEND_RTC") } func (e *environment) DefaultBackendSRT() string { - return os.Getenv("PROXY_DEFAULT_BACKEND_SRT") + return getEnv("PROXY_DEFAULT_BACKEND_SRT") } // loadEnvFile loads the environment variables from .env file. @@ -171,16 +183,10 @@ func loadEnvFile(ctx context.Context) error { return errors.Wrapf(err, "load .env file") } - // Build a set of existing environment variable keys, so we don't overwrite them. - currentEnv := make(map[string]bool) - for _, entry := range os.Environ() { - key, _, _ := strings.Cut(entry, "=") - currentEnv[key] = true - } - + // Skip keys already set in the environment so we don't overwrite them. for key, value := range envMap { - if !currentEnv[key] { - os.Setenv(key, value) + if _, ok := lookupEnv(key); !ok { + setEnv(key, value) } } @@ -188,16 +194,21 @@ func loadEnvFile(ctx context.Context) error { return nil } -// parseEnvFile reads a .env file and returns a map of key-value pairs. +// parseEnvFile opens filename and parses its contents as .env-formatted lines. func parseEnvFile(filename string) (map[string]string, error) { - file, err := os.Open(filename) + file, err := openFile(filename) if err != nil { return nil, err } defer file.Close() + return parseEnvReader(file) +} +// parseEnvReader parses .env-formatted content from r. It performs no I/O +// beyond reading r, so it is trivially testable with strings.NewReader. +func parseEnvReader(r io.Reader) (map[string]string, error) { envMap := make(map[string]string) - scanner := bufio.NewScanner(file) + scanner := bufio.NewScanner(r) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -314,22 +325,22 @@ func buildDefaultEnvironmentVariables(ctx context.Context) { "PROXY_DEFAULT_BACKEND_RTC=%v, PROXY_DEFAULT_BACKEND_SRT=%v, "+ "PROXY_LOAD_BALANCER_TYPE=%v, PROXY_REDIS_HOST=%v, PROXY_REDIS_PORT=%v, "+ "PROXY_REDIS_PASSWORD=%v, PROXY_REDIS_DB=%v", - os.Getenv("GO_PPROF"), - os.Getenv("PROXY_FORCE_QUIT_TIMEOUT"), os.Getenv("PROXY_GRACE_QUIT_TIMEOUT"), - os.Getenv("PROXY_HTTP_API"), os.Getenv("PROXY_HTTP_SERVER"), os.Getenv("PROXY_RTMP_SERVER"), - os.Getenv("PROXY_WEBRTC_SERVER"), os.Getenv("PROXY_SRT_SERVER"), - os.Getenv("PROXY_SYSTEM_API"), os.Getenv("PROXY_STATIC_FILES"), os.Getenv("PROXY_DEFAULT_BACKEND_ENABLED"), - os.Getenv("PROXY_DEFAULT_BACKEND_IP"), os.Getenv("PROXY_DEFAULT_BACKEND_RTMP"), - os.Getenv("PROXY_DEFAULT_BACKEND_HTTP"), os.Getenv("PROXY_DEFAULT_BACKEND_API"), - os.Getenv("PROXY_DEFAULT_BACKEND_RTC"), os.Getenv("PROXY_DEFAULT_BACKEND_SRT"), - os.Getenv("PROXY_LOAD_BALANCER_TYPE"), os.Getenv("PROXY_REDIS_HOST"), os.Getenv("PROXY_REDIS_PORT"), - os.Getenv("PROXY_REDIS_PASSWORD"), os.Getenv("PROXY_REDIS_DB"), + getEnv("GO_PPROF"), + getEnv("PROXY_FORCE_QUIT_TIMEOUT"), getEnv("PROXY_GRACE_QUIT_TIMEOUT"), + getEnv("PROXY_HTTP_API"), getEnv("PROXY_HTTP_SERVER"), getEnv("PROXY_RTMP_SERVER"), + getEnv("PROXY_WEBRTC_SERVER"), getEnv("PROXY_SRT_SERVER"), + getEnv("PROXY_SYSTEM_API"), getEnv("PROXY_STATIC_FILES"), getEnv("PROXY_DEFAULT_BACKEND_ENABLED"), + getEnv("PROXY_DEFAULT_BACKEND_IP"), getEnv("PROXY_DEFAULT_BACKEND_RTMP"), + getEnv("PROXY_DEFAULT_BACKEND_HTTP"), getEnv("PROXY_DEFAULT_BACKEND_API"), + getEnv("PROXY_DEFAULT_BACKEND_RTC"), getEnv("PROXY_DEFAULT_BACKEND_SRT"), + getEnv("PROXY_LOAD_BALANCER_TYPE"), getEnv("PROXY_REDIS_HOST"), getEnv("PROXY_REDIS_PORT"), + getEnv("PROXY_REDIS_PASSWORD"), getEnv("PROXY_REDIS_DB"), ) } // setEnvDefault set env key=value if not set. func setEnvDefault(key, value string) { - if os.Getenv(key) == "" { - os.Setenv(key, value) + if getEnv(key) == "" { + setEnv(key, value) } } diff --git a/internal/env/env_test.go b/internal/env/env_test.go index ffe78a840..49fa138d9 100644 --- a/internal/env/env_test.go +++ b/internal/env/env_test.go @@ -4,15 +4,59 @@ package env import ( + "context" + "errors" + "io" "os" - "path/filepath" "strings" "testing" + + srserrors "srsx/internal/errors" ) -func TestParseEnvFile_BasicKeyValue(t *testing.T) { - f := writeTempEnv(t, "FOO=bar\nHELLO=world\n") - m, err := parseEnvFile(f) +// fakeEnv is an in-memory replacement for process environment variables. +// Tests install it via withFakeEnv so no real os.Setenv/os.Getenv call is +// ever made, which keeps tests hermetic and free of global side effects. +type fakeEnv struct { + store map[string]string +} + +func (f *fakeEnv) get(k string) string { return f.store[k] } +func (f *fakeEnv) set(k, v string) error { f.store[k] = v; return nil } +func (f *fakeEnv) lookup(k string) (string, bool) { + v, ok := f.store[k] + return v, ok +} + +// withFakeEnv swaps getEnv/setEnv/lookupEnv to an in-memory map for the +// duration of the test and restores the originals on cleanup. +func withFakeEnv(t *testing.T) *fakeEnv { + t.Helper() + fe := &fakeEnv{store: map[string]string{}} + origGet, origSet, origLookup := getEnv, setEnv, lookupEnv + getEnv, setEnv, lookupEnv = fe.get, fe.set, fe.lookup + t.Cleanup(func() { + getEnv, setEnv, lookupEnv = origGet, origSet, origLookup + }) + return fe +} + +// withFakeOpen swaps openFile to return either content or err, and +// restores the original on cleanup. If err is non-nil, content is ignored. +func withFakeOpen(t *testing.T, content string, err error) { + t.Helper() + orig := openFile + openFile = func(string) (io.ReadCloser, error) { + if err != nil { + return nil, err + } + return io.NopCloser(strings.NewReader(content)), nil + } + t.Cleanup(func() { openFile = orig }) +} + +func TestParseEnvReader_BasicKeyValue(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("FOO=bar\nHELLO=world\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -24,9 +68,8 @@ func TestParseEnvFile_BasicKeyValue(t *testing.T) { } } -func TestParseEnvFile_SkipCommentsAndBlankLines(t *testing.T) { - f := writeTempEnv(t, "# this is a comment\n\nKEY=value\n\n# another comment\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_SkipCommentsAndBlankLines(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("# this is a comment\n\nKEY=value\n\n# another comment\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -38,9 +81,8 @@ func TestParseEnvFile_SkipCommentsAndBlankLines(t *testing.T) { } } -func TestParseEnvFile_ExportPrefix(t *testing.T) { - f := writeTempEnv(t, "export PORT=8080\nexport HOST=localhost\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_ExportPrefix(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("export PORT=8080\nexport HOST=localhost\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -52,24 +94,21 @@ func TestParseEnvFile_ExportPrefix(t *testing.T) { } } -func TestParseEnvFile_SingleQuoted(t *testing.T) { - f := writeTempEnv(t, "KEY='hello world'\nRAW='no\\nescaping'\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_SingleQuoted(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("KEY='hello world'\nRAW='no\\nescaping'\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } if m["KEY"] != "hello world" { t.Errorf("KEY = %q, want %q", m["KEY"], "hello world") } - // Single quotes: backslash-n stays literal. if m["RAW"] != `no\nescaping` { t.Errorf("RAW = %q, want %q", m["RAW"], `no\nescaping`) } } -func TestParseEnvFile_DoubleQuoted(t *testing.T) { - f := writeTempEnv(t, `KEY="hello world"`+"\n"+`MSG="line1\nline2"`+"\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_DoubleQuoted(t *testing.T) { + m, err := parseEnvReader(strings.NewReader(`KEY="hello world"` + "\n" + `MSG="line1\nline2"` + "\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -81,9 +120,8 @@ func TestParseEnvFile_DoubleQuoted(t *testing.T) { } } -func TestParseEnvFile_DoubleQuotedEscapes(t *testing.T) { - f := writeTempEnv(t, `KEY="say \"hi\""`+"\n"+`BS="back\\slash"`+"\n"+`CR="a\rb"`+"\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_DoubleQuotedEscapes(t *testing.T) { + m, err := parseEnvReader(strings.NewReader(`KEY="say \"hi\""` + "\n" + `BS="back\\slash"` + "\n" + `CR="a\rb"` + "\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -98,9 +136,8 @@ func TestParseEnvFile_DoubleQuotedEscapes(t *testing.T) { } } -func TestParseEnvFile_InlineComment(t *testing.T) { - f := writeTempEnv(t, "KEY=value # this is a comment\nNUM=42 # the answer\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_InlineComment(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("KEY=value # this is a comment\nNUM=42 # the answer\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -112,9 +149,8 @@ func TestParseEnvFile_InlineComment(t *testing.T) { } } -func TestParseEnvFile_NoEqualsSign(t *testing.T) { - f := writeTempEnv(t, "NOEQUALS\nKEY=value\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_NoEqualsSign(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("NOEQUALS\nKEY=value\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -126,9 +162,8 @@ func TestParseEnvFile_NoEqualsSign(t *testing.T) { } } -func TestParseEnvFile_EmptyValue(t *testing.T) { - f := writeTempEnv(t, "KEY=\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_EmptyValue(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("KEY=\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -137,9 +172,8 @@ func TestParseEnvFile_EmptyValue(t *testing.T) { } } -func TestParseEnvFile_ValueWithEquals(t *testing.T) { - f := writeTempEnv(t, "URL=postgres://host:5432/db?opt=val\n") - m, err := parseEnvFile(f) +func TestParseEnvReader_ValueWithEquals(t *testing.T) { + m, err := parseEnvReader(strings.NewReader("URL=postgres://host:5432/db?opt=val\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -148,19 +182,8 @@ func TestParseEnvFile_ValueWithEquals(t *testing.T) { } } -func TestParseEnvFile_FileNotFound(t *testing.T) { - _, err := parseEnvFile("/nonexistent/.env") - if err == nil { - t.Fatal("expected error for missing file") - } - if !os.IsNotExist(err) { - t.Errorf("expected os.IsNotExist, got: %v", err) - } -} - -func TestParseEnvFile_WhitespaceAroundKeyValue(t *testing.T) { - f := writeTempEnv(t, " KEY = value \n") - m, err := parseEnvFile(f) +func TestParseEnvReader_WhitespaceAroundKeyValue(t *testing.T) { + m, err := parseEnvReader(strings.NewReader(" KEY = value \n")) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -169,55 +192,187 @@ func TestParseEnvFile_WhitespaceAroundKeyValue(t *testing.T) { } } -func TestLoadEnvFile_DoesNotOverwriteExisting(t *testing.T) { - // Write a .env file in a temp dir. - dir := t.TempDir() - envFile := filepath.Join(dir, ".env") - if err := os.WriteFile(envFile, []byte("TEST_EXISTING=fromfile\nTEST_NEW=fromfile\n"), 0644); err != nil { - t.Fatalf("write .env: %v", err) - } - - // Pre-set one of the keys in the real environment. - os.Setenv("TEST_EXISTING", "fromshell") - t.Cleanup(func() { - os.Unsetenv("TEST_EXISTING") - os.Unsetenv("TEST_NEW") - }) - - // Parse and apply, mimicking loadEnvFile logic. - m, err := parseEnvFile(envFile) +func TestParseEnvReader_ShortValue(t *testing.T) { + // Single-character value exercises the len(value) < 2 short-value branch. + m, err := parseEnvReader(strings.NewReader("A=x\nB=y\n")) if err != nil { t.Fatalf("unexpected error: %v", err) } - - currentEnv := make(map[string]bool) - for _, entry := range os.Environ() { - k, _, _ := strings.Cut(entry, "=") - currentEnv[k] = true + if m["A"] != "x" { + t.Errorf("A = %q, want %q", m["A"], "x") } - for k, v := range m { - if !currentEnv[k] { - os.Setenv(k, v) - } + if m["B"] != "y" { + t.Errorf("B = %q, want %q", m["B"], "y") } +} - // Existing key should NOT be overwritten. - if got := os.Getenv("TEST_EXISTING"); got != "fromshell" { +func TestParseEnvFile_FileNotFound(t *testing.T) { + withFakeOpen(t, "", os.ErrNotExist) + _, err := parseEnvFile(".env") + if !errors.Is(err, os.ErrNotExist) { + t.Errorf("expected os.ErrNotExist, got: %v", err) + } +} + +func TestParseEnvFile_OpenError(t *testing.T) { + // A non-NotExist open error should bubble up as-is. + sentinel := errors.New("boom") + withFakeOpen(t, "", sentinel) + _, err := parseEnvFile(".env") + if !errors.Is(err, sentinel) { + t.Errorf("expected sentinel error, got: %v", err) + } +} + +func TestParseEnvFile_DelegatesToReader(t *testing.T) { + withFakeOpen(t, "FOO=bar\n", nil) + m, err := parseEnvFile(".env") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if m["FOO"] != "bar" { + t.Errorf("FOO = %q, want %q", m["FOO"], "bar") + } +} + +func TestLoadEnvFile_DoesNotOverwriteExisting(t *testing.T) { + fe := withFakeEnv(t) + fe.store["TEST_EXISTING"] = "fromshell" + // TEST_NEW is absent from the store, so it should be loaded from the file. + withFakeOpen(t, "TEST_EXISTING=fromfile\nTEST_NEW=fromfile\n", nil) + + if err := loadEnvFile(context.Background()); err != nil { + t.Fatalf("loadEnvFile: %v", err) + } + if got := fe.store["TEST_EXISTING"]; got != "fromshell" { t.Errorf("TEST_EXISTING = %q, want %q (should not overwrite)", got, "fromshell") } - // New key should be set. - if got := os.Getenv("TEST_NEW"); got != "fromfile" { + if got := fe.store["TEST_NEW"]; got != "fromfile" { t.Errorf("TEST_NEW = %q, want %q", got, "fromfile") } } -// writeTempEnv writes content to a temp .env file and returns the path. -func writeTempEnv(t *testing.T, content string) string { - t.Helper() - dir := t.TempDir() - f := filepath.Join(dir, ".env") - if err := os.WriteFile(f, []byte(content), 0644); err != nil { - t.Fatalf("write temp .env: %v", err) +func TestLoadEnvFile_NoFileIsNoError(t *testing.T) { + withFakeEnv(t) + withFakeOpen(t, "", os.ErrNotExist) + if err := loadEnvFile(context.Background()); err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +func TestLoadEnvFile_OpenErrorIsWrapped(t *testing.T) { + withFakeEnv(t) + sentinel := errors.New("disk gone") + withFakeOpen(t, "", sentinel) + err := loadEnvFile(context.Background()) + if err == nil { + t.Fatal("expected error, got nil") + } + if srserrors.Cause(err) != sentinel { + t.Errorf("expected wrapped sentinel, got: %v", err) + } +} + +func TestLoadEnvFile_AppliesFromFile(t *testing.T) { + fe := withFakeEnv(t) + withFakeOpen(t, "TEST_LOAD_ENV_FILE_APPLIES=loaded\n", nil) + + if err := loadEnvFile(context.Background()); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got := fe.store["TEST_LOAD_ENV_FILE_APPLIES"]; got != "loaded" { + t.Errorf("got %q, want %q", got, "loaded") + } +} + +func TestSetEnvDefault_SetsWhenEmpty(t *testing.T) { + fe := withFakeEnv(t) + // Key is absent (getEnv returns ""), so the default should apply. + setEnvDefault("KEY", "defaultVal") + if got := fe.store["KEY"]; got != "defaultVal" { + t.Errorf("KEY = %q, want %q", got, "defaultVal") + } +} + +func TestSetEnvDefault_PreservesExisting(t *testing.T) { + fe := withFakeEnv(t) + fe.store["KEY"] = "original" + setEnvDefault("KEY", "shouldNotApply") + if got := fe.store["KEY"]; got != "original" { + t.Errorf("KEY = %q, want %q", got, "original") + } +} + +func TestNewEnvironment_AppliesDefaultsAndAccessors(t *testing.T) { + withFakeEnv(t) + // No .env file present. + withFakeOpen(t, "", os.ErrNotExist) + + // PROXY_DEFAULT_BACKEND_HTTP has no default in buildDefaultEnvironmentVariables; + // pre-set it so the accessor has a value to return. + setEnv("PROXY_DEFAULT_BACKEND_HTTP", "8080") + + env, err := NewEnvironment(context.Background()) + if err != nil { + t.Fatalf("NewEnvironment: %v", err) + } + + cases := []struct { + name string + got string + want string + }{ + {"GoPprof", env.GoPprof(), ""}, + {"GraceQuitTimeout", env.GraceQuitTimeout(), "20s"}, + {"ForceQuitTimeout", env.ForceQuitTimeout(), "30s"}, + {"HttpAPI", env.HttpAPI(), "11985"}, + {"HttpServer", env.HttpServer(), "18080"}, + {"RtmpServer", env.RtmpServer(), "11935"}, + {"WebRTCServer", env.WebRTCServer(), "18000"}, + {"SRTServer", env.SRTServer(), "20080"}, + {"SystemAPI", env.SystemAPI(), "12025"}, + {"StaticFiles", env.StaticFiles(), "./trunk/research"}, + {"LoadBalancerType", env.LoadBalancerType(), "memory"}, + {"RedisHost", env.RedisHost(), "127.0.0.1"}, + {"RedisPort", env.RedisPort(), "6379"}, + {"RedisPassword", env.RedisPassword(), ""}, + {"RedisDB", env.RedisDB(), "0"}, + {"DefaultBackendEnabled", env.DefaultBackendEnabled(), "off"}, + {"DefaultBackendIP", env.DefaultBackendIP(), "127.0.0.1"}, + {"DefaultBackendRTMP", env.DefaultBackendRTMP(), "1935"}, + {"DefaultBackendHttp", env.DefaultBackendHttp(), "8080"}, + {"DefaultBackendAPI", env.DefaultBackendAPI(), "1985"}, + {"DefaultBackendRTC", env.DefaultBackendRTC(), "8000"}, + {"DefaultBackendSRT", env.DefaultBackendSRT(), "10080"}, + } + for _, c := range cases { + if c.got != c.want { + t.Errorf("%s() = %q, want %q", c.name, c.got, c.want) + } + } +} + +func TestNewEnvironment_PreservesPreSetValues(t *testing.T) { + withFakeEnv(t) + withFakeOpen(t, "", os.ErrNotExist) + setEnv("PROXY_HTTP_API", "9999") + + env, err := NewEnvironment(context.Background()) + if err != nil { + t.Fatalf("NewEnvironment: %v", err) + } + if got := env.HttpAPI(); got != "9999" { + t.Errorf("HttpAPI() = %q, want %q", got, "9999") + } +} + +func TestNewEnvironment_LoadEnvFailurePropagates(t *testing.T) { + withFakeEnv(t) + sentinel := errors.New("open failed") + withFakeOpen(t, "", sentinel) + + _, err := NewEnvironment(context.Background()) + if srserrors.Cause(err) != sentinel { + t.Errorf("expected wrapped sentinel, got: %v", err) } - return f } diff --git a/internal/env/envfakes/fake_environment.go b/internal/env/envfakes/fake_environment.go new file mode 100644 index 000000000..165ae7a1d --- /dev/null +++ b/internal/env/envfakes/fake_environment.go @@ -0,0 +1,1422 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package envfakes + +import ( + "srsx/internal/env" + "sync" +) + +type FakeEnvironment struct { + DefaultBackendAPIStub func() string + defaultBackendAPIMutex sync.RWMutex + defaultBackendAPIArgsForCall []struct { + } + defaultBackendAPIReturns struct { + result1 string + } + defaultBackendAPIReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendEnabledStub func() string + defaultBackendEnabledMutex sync.RWMutex + defaultBackendEnabledArgsForCall []struct { + } + defaultBackendEnabledReturns struct { + result1 string + } + defaultBackendEnabledReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendHttpStub func() string + defaultBackendHttpMutex sync.RWMutex + defaultBackendHttpArgsForCall []struct { + } + defaultBackendHttpReturns struct { + result1 string + } + defaultBackendHttpReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendIPStub func() string + defaultBackendIPMutex sync.RWMutex + defaultBackendIPArgsForCall []struct { + } + defaultBackendIPReturns struct { + result1 string + } + defaultBackendIPReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendRTCStub func() string + defaultBackendRTCMutex sync.RWMutex + defaultBackendRTCArgsForCall []struct { + } + defaultBackendRTCReturns struct { + result1 string + } + defaultBackendRTCReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendRTMPStub func() string + defaultBackendRTMPMutex sync.RWMutex + defaultBackendRTMPArgsForCall []struct { + } + defaultBackendRTMPReturns struct { + result1 string + } + defaultBackendRTMPReturnsOnCall map[int]struct { + result1 string + } + DefaultBackendSRTStub func() string + defaultBackendSRTMutex sync.RWMutex + defaultBackendSRTArgsForCall []struct { + } + defaultBackendSRTReturns struct { + result1 string + } + defaultBackendSRTReturnsOnCall map[int]struct { + result1 string + } + ForceQuitTimeoutStub func() string + forceQuitTimeoutMutex sync.RWMutex + forceQuitTimeoutArgsForCall []struct { + } + forceQuitTimeoutReturns struct { + result1 string + } + forceQuitTimeoutReturnsOnCall map[int]struct { + result1 string + } + GoPprofStub func() string + goPprofMutex sync.RWMutex + goPprofArgsForCall []struct { + } + goPprofReturns struct { + result1 string + } + goPprofReturnsOnCall map[int]struct { + result1 string + } + GraceQuitTimeoutStub func() string + graceQuitTimeoutMutex sync.RWMutex + graceQuitTimeoutArgsForCall []struct { + } + graceQuitTimeoutReturns struct { + result1 string + } + graceQuitTimeoutReturnsOnCall map[int]struct { + result1 string + } + HttpAPIStub func() string + httpAPIMutex sync.RWMutex + httpAPIArgsForCall []struct { + } + httpAPIReturns struct { + result1 string + } + httpAPIReturnsOnCall map[int]struct { + result1 string + } + HttpServerStub func() string + httpServerMutex sync.RWMutex + httpServerArgsForCall []struct { + } + httpServerReturns struct { + result1 string + } + httpServerReturnsOnCall map[int]struct { + result1 string + } + LoadBalancerTypeStub func() string + loadBalancerTypeMutex sync.RWMutex + loadBalancerTypeArgsForCall []struct { + } + loadBalancerTypeReturns struct { + result1 string + } + loadBalancerTypeReturnsOnCall map[int]struct { + result1 string + } + RedisDBStub func() string + redisDBMutex sync.RWMutex + redisDBArgsForCall []struct { + } + redisDBReturns struct { + result1 string + } + redisDBReturnsOnCall map[int]struct { + result1 string + } + RedisHostStub func() string + redisHostMutex sync.RWMutex + redisHostArgsForCall []struct { + } + redisHostReturns struct { + result1 string + } + redisHostReturnsOnCall map[int]struct { + result1 string + } + RedisPasswordStub func() string + redisPasswordMutex sync.RWMutex + redisPasswordArgsForCall []struct { + } + redisPasswordReturns struct { + result1 string + } + redisPasswordReturnsOnCall map[int]struct { + result1 string + } + RedisPortStub func() string + redisPortMutex sync.RWMutex + redisPortArgsForCall []struct { + } + redisPortReturns struct { + result1 string + } + redisPortReturnsOnCall map[int]struct { + result1 string + } + RtmpServerStub func() string + rtmpServerMutex sync.RWMutex + rtmpServerArgsForCall []struct { + } + rtmpServerReturns struct { + result1 string + } + rtmpServerReturnsOnCall map[int]struct { + result1 string + } + SRTServerStub func() string + sRTServerMutex sync.RWMutex + sRTServerArgsForCall []struct { + } + sRTServerReturns struct { + result1 string + } + sRTServerReturnsOnCall map[int]struct { + result1 string + } + StaticFilesStub func() string + staticFilesMutex sync.RWMutex + staticFilesArgsForCall []struct { + } + staticFilesReturns struct { + result1 string + } + staticFilesReturnsOnCall map[int]struct { + result1 string + } + SystemAPIStub func() string + systemAPIMutex sync.RWMutex + systemAPIArgsForCall []struct { + } + systemAPIReturns struct { + result1 string + } + systemAPIReturnsOnCall map[int]struct { + result1 string + } + WebRTCServerStub func() string + webRTCServerMutex sync.RWMutex + webRTCServerArgsForCall []struct { + } + webRTCServerReturns struct { + result1 string + } + webRTCServerReturnsOnCall map[int]struct { + result1 string + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeEnvironment) DefaultBackendAPI() string { + fake.defaultBackendAPIMutex.Lock() + ret, specificReturn := fake.defaultBackendAPIReturnsOnCall[len(fake.defaultBackendAPIArgsForCall)] + fake.defaultBackendAPIArgsForCall = append(fake.defaultBackendAPIArgsForCall, struct { + }{}) + stub := fake.DefaultBackendAPIStub + fakeReturns := fake.defaultBackendAPIReturns + fake.recordInvocation("DefaultBackendAPI", []interface{}{}) + fake.defaultBackendAPIMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendAPICallCount() int { + fake.defaultBackendAPIMutex.RLock() + defer fake.defaultBackendAPIMutex.RUnlock() + return len(fake.defaultBackendAPIArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendAPICalls(stub func() string) { + fake.defaultBackendAPIMutex.Lock() + defer fake.defaultBackendAPIMutex.Unlock() + fake.DefaultBackendAPIStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendAPIReturns(result1 string) { + fake.defaultBackendAPIMutex.Lock() + defer fake.defaultBackendAPIMutex.Unlock() + fake.DefaultBackendAPIStub = nil + fake.defaultBackendAPIReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendAPIReturnsOnCall(i int, result1 string) { + fake.defaultBackendAPIMutex.Lock() + defer fake.defaultBackendAPIMutex.Unlock() + fake.DefaultBackendAPIStub = nil + if fake.defaultBackendAPIReturnsOnCall == nil { + fake.defaultBackendAPIReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendAPIReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendEnabled() string { + fake.defaultBackendEnabledMutex.Lock() + ret, specificReturn := fake.defaultBackendEnabledReturnsOnCall[len(fake.defaultBackendEnabledArgsForCall)] + fake.defaultBackendEnabledArgsForCall = append(fake.defaultBackendEnabledArgsForCall, struct { + }{}) + stub := fake.DefaultBackendEnabledStub + fakeReturns := fake.defaultBackendEnabledReturns + fake.recordInvocation("DefaultBackendEnabled", []interface{}{}) + fake.defaultBackendEnabledMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendEnabledCallCount() int { + fake.defaultBackendEnabledMutex.RLock() + defer fake.defaultBackendEnabledMutex.RUnlock() + return len(fake.defaultBackendEnabledArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendEnabledCalls(stub func() string) { + fake.defaultBackendEnabledMutex.Lock() + defer fake.defaultBackendEnabledMutex.Unlock() + fake.DefaultBackendEnabledStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendEnabledReturns(result1 string) { + fake.defaultBackendEnabledMutex.Lock() + defer fake.defaultBackendEnabledMutex.Unlock() + fake.DefaultBackendEnabledStub = nil + fake.defaultBackendEnabledReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendEnabledReturnsOnCall(i int, result1 string) { + fake.defaultBackendEnabledMutex.Lock() + defer fake.defaultBackendEnabledMutex.Unlock() + fake.DefaultBackendEnabledStub = nil + if fake.defaultBackendEnabledReturnsOnCall == nil { + fake.defaultBackendEnabledReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendEnabledReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendHttp() string { + fake.defaultBackendHttpMutex.Lock() + ret, specificReturn := fake.defaultBackendHttpReturnsOnCall[len(fake.defaultBackendHttpArgsForCall)] + fake.defaultBackendHttpArgsForCall = append(fake.defaultBackendHttpArgsForCall, struct { + }{}) + stub := fake.DefaultBackendHttpStub + fakeReturns := fake.defaultBackendHttpReturns + fake.recordInvocation("DefaultBackendHttp", []interface{}{}) + fake.defaultBackendHttpMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendHttpCallCount() int { + fake.defaultBackendHttpMutex.RLock() + defer fake.defaultBackendHttpMutex.RUnlock() + return len(fake.defaultBackendHttpArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendHttpCalls(stub func() string) { + fake.defaultBackendHttpMutex.Lock() + defer fake.defaultBackendHttpMutex.Unlock() + fake.DefaultBackendHttpStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendHttpReturns(result1 string) { + fake.defaultBackendHttpMutex.Lock() + defer fake.defaultBackendHttpMutex.Unlock() + fake.DefaultBackendHttpStub = nil + fake.defaultBackendHttpReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendHttpReturnsOnCall(i int, result1 string) { + fake.defaultBackendHttpMutex.Lock() + defer fake.defaultBackendHttpMutex.Unlock() + fake.DefaultBackendHttpStub = nil + if fake.defaultBackendHttpReturnsOnCall == nil { + fake.defaultBackendHttpReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendHttpReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendIP() string { + fake.defaultBackendIPMutex.Lock() + ret, specificReturn := fake.defaultBackendIPReturnsOnCall[len(fake.defaultBackendIPArgsForCall)] + fake.defaultBackendIPArgsForCall = append(fake.defaultBackendIPArgsForCall, struct { + }{}) + stub := fake.DefaultBackendIPStub + fakeReturns := fake.defaultBackendIPReturns + fake.recordInvocation("DefaultBackendIP", []interface{}{}) + fake.defaultBackendIPMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendIPCallCount() int { + fake.defaultBackendIPMutex.RLock() + defer fake.defaultBackendIPMutex.RUnlock() + return len(fake.defaultBackendIPArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendIPCalls(stub func() string) { + fake.defaultBackendIPMutex.Lock() + defer fake.defaultBackendIPMutex.Unlock() + fake.DefaultBackendIPStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendIPReturns(result1 string) { + fake.defaultBackendIPMutex.Lock() + defer fake.defaultBackendIPMutex.Unlock() + fake.DefaultBackendIPStub = nil + fake.defaultBackendIPReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendIPReturnsOnCall(i int, result1 string) { + fake.defaultBackendIPMutex.Lock() + defer fake.defaultBackendIPMutex.Unlock() + fake.DefaultBackendIPStub = nil + if fake.defaultBackendIPReturnsOnCall == nil { + fake.defaultBackendIPReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendIPReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendRTC() string { + fake.defaultBackendRTCMutex.Lock() + ret, specificReturn := fake.defaultBackendRTCReturnsOnCall[len(fake.defaultBackendRTCArgsForCall)] + fake.defaultBackendRTCArgsForCall = append(fake.defaultBackendRTCArgsForCall, struct { + }{}) + stub := fake.DefaultBackendRTCStub + fakeReturns := fake.defaultBackendRTCReturns + fake.recordInvocation("DefaultBackendRTC", []interface{}{}) + fake.defaultBackendRTCMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendRTCCallCount() int { + fake.defaultBackendRTCMutex.RLock() + defer fake.defaultBackendRTCMutex.RUnlock() + return len(fake.defaultBackendRTCArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendRTCCalls(stub func() string) { + fake.defaultBackendRTCMutex.Lock() + defer fake.defaultBackendRTCMutex.Unlock() + fake.DefaultBackendRTCStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendRTCReturns(result1 string) { + fake.defaultBackendRTCMutex.Lock() + defer fake.defaultBackendRTCMutex.Unlock() + fake.DefaultBackendRTCStub = nil + fake.defaultBackendRTCReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendRTCReturnsOnCall(i int, result1 string) { + fake.defaultBackendRTCMutex.Lock() + defer fake.defaultBackendRTCMutex.Unlock() + fake.DefaultBackendRTCStub = nil + if fake.defaultBackendRTCReturnsOnCall == nil { + fake.defaultBackendRTCReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendRTCReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendRTMP() string { + fake.defaultBackendRTMPMutex.Lock() + ret, specificReturn := fake.defaultBackendRTMPReturnsOnCall[len(fake.defaultBackendRTMPArgsForCall)] + fake.defaultBackendRTMPArgsForCall = append(fake.defaultBackendRTMPArgsForCall, struct { + }{}) + stub := fake.DefaultBackendRTMPStub + fakeReturns := fake.defaultBackendRTMPReturns + fake.recordInvocation("DefaultBackendRTMP", []interface{}{}) + fake.defaultBackendRTMPMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendRTMPCallCount() int { + fake.defaultBackendRTMPMutex.RLock() + defer fake.defaultBackendRTMPMutex.RUnlock() + return len(fake.defaultBackendRTMPArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendRTMPCalls(stub func() string) { + fake.defaultBackendRTMPMutex.Lock() + defer fake.defaultBackendRTMPMutex.Unlock() + fake.DefaultBackendRTMPStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendRTMPReturns(result1 string) { + fake.defaultBackendRTMPMutex.Lock() + defer fake.defaultBackendRTMPMutex.Unlock() + fake.DefaultBackendRTMPStub = nil + fake.defaultBackendRTMPReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendRTMPReturnsOnCall(i int, result1 string) { + fake.defaultBackendRTMPMutex.Lock() + defer fake.defaultBackendRTMPMutex.Unlock() + fake.DefaultBackendRTMPStub = nil + if fake.defaultBackendRTMPReturnsOnCall == nil { + fake.defaultBackendRTMPReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendRTMPReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendSRT() string { + fake.defaultBackendSRTMutex.Lock() + ret, specificReturn := fake.defaultBackendSRTReturnsOnCall[len(fake.defaultBackendSRTArgsForCall)] + fake.defaultBackendSRTArgsForCall = append(fake.defaultBackendSRTArgsForCall, struct { + }{}) + stub := fake.DefaultBackendSRTStub + fakeReturns := fake.defaultBackendSRTReturns + fake.recordInvocation("DefaultBackendSRT", []interface{}{}) + fake.defaultBackendSRTMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) DefaultBackendSRTCallCount() int { + fake.defaultBackendSRTMutex.RLock() + defer fake.defaultBackendSRTMutex.RUnlock() + return len(fake.defaultBackendSRTArgsForCall) +} + +func (fake *FakeEnvironment) DefaultBackendSRTCalls(stub func() string) { + fake.defaultBackendSRTMutex.Lock() + defer fake.defaultBackendSRTMutex.Unlock() + fake.DefaultBackendSRTStub = stub +} + +func (fake *FakeEnvironment) DefaultBackendSRTReturns(result1 string) { + fake.defaultBackendSRTMutex.Lock() + defer fake.defaultBackendSRTMutex.Unlock() + fake.DefaultBackendSRTStub = nil + fake.defaultBackendSRTReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) DefaultBackendSRTReturnsOnCall(i int, result1 string) { + fake.defaultBackendSRTMutex.Lock() + defer fake.defaultBackendSRTMutex.Unlock() + fake.DefaultBackendSRTStub = nil + if fake.defaultBackendSRTReturnsOnCall == nil { + fake.defaultBackendSRTReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.defaultBackendSRTReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) ForceQuitTimeout() string { + fake.forceQuitTimeoutMutex.Lock() + ret, specificReturn := fake.forceQuitTimeoutReturnsOnCall[len(fake.forceQuitTimeoutArgsForCall)] + fake.forceQuitTimeoutArgsForCall = append(fake.forceQuitTimeoutArgsForCall, struct { + }{}) + stub := fake.ForceQuitTimeoutStub + fakeReturns := fake.forceQuitTimeoutReturns + fake.recordInvocation("ForceQuitTimeout", []interface{}{}) + fake.forceQuitTimeoutMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) ForceQuitTimeoutCallCount() int { + fake.forceQuitTimeoutMutex.RLock() + defer fake.forceQuitTimeoutMutex.RUnlock() + return len(fake.forceQuitTimeoutArgsForCall) +} + +func (fake *FakeEnvironment) ForceQuitTimeoutCalls(stub func() string) { + fake.forceQuitTimeoutMutex.Lock() + defer fake.forceQuitTimeoutMutex.Unlock() + fake.ForceQuitTimeoutStub = stub +} + +func (fake *FakeEnvironment) ForceQuitTimeoutReturns(result1 string) { + fake.forceQuitTimeoutMutex.Lock() + defer fake.forceQuitTimeoutMutex.Unlock() + fake.ForceQuitTimeoutStub = nil + fake.forceQuitTimeoutReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) ForceQuitTimeoutReturnsOnCall(i int, result1 string) { + fake.forceQuitTimeoutMutex.Lock() + defer fake.forceQuitTimeoutMutex.Unlock() + fake.ForceQuitTimeoutStub = nil + if fake.forceQuitTimeoutReturnsOnCall == nil { + fake.forceQuitTimeoutReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.forceQuitTimeoutReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) GoPprof() string { + fake.goPprofMutex.Lock() + ret, specificReturn := fake.goPprofReturnsOnCall[len(fake.goPprofArgsForCall)] + fake.goPprofArgsForCall = append(fake.goPprofArgsForCall, struct { + }{}) + stub := fake.GoPprofStub + fakeReturns := fake.goPprofReturns + fake.recordInvocation("GoPprof", []interface{}{}) + fake.goPprofMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) GoPprofCallCount() int { + fake.goPprofMutex.RLock() + defer fake.goPprofMutex.RUnlock() + return len(fake.goPprofArgsForCall) +} + +func (fake *FakeEnvironment) GoPprofCalls(stub func() string) { + fake.goPprofMutex.Lock() + defer fake.goPprofMutex.Unlock() + fake.GoPprofStub = stub +} + +func (fake *FakeEnvironment) GoPprofReturns(result1 string) { + fake.goPprofMutex.Lock() + defer fake.goPprofMutex.Unlock() + fake.GoPprofStub = nil + fake.goPprofReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) GoPprofReturnsOnCall(i int, result1 string) { + fake.goPprofMutex.Lock() + defer fake.goPprofMutex.Unlock() + fake.GoPprofStub = nil + if fake.goPprofReturnsOnCall == nil { + fake.goPprofReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.goPprofReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) GraceQuitTimeout() string { + fake.graceQuitTimeoutMutex.Lock() + ret, specificReturn := fake.graceQuitTimeoutReturnsOnCall[len(fake.graceQuitTimeoutArgsForCall)] + fake.graceQuitTimeoutArgsForCall = append(fake.graceQuitTimeoutArgsForCall, struct { + }{}) + stub := fake.GraceQuitTimeoutStub + fakeReturns := fake.graceQuitTimeoutReturns + fake.recordInvocation("GraceQuitTimeout", []interface{}{}) + fake.graceQuitTimeoutMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) GraceQuitTimeoutCallCount() int { + fake.graceQuitTimeoutMutex.RLock() + defer fake.graceQuitTimeoutMutex.RUnlock() + return len(fake.graceQuitTimeoutArgsForCall) +} + +func (fake *FakeEnvironment) GraceQuitTimeoutCalls(stub func() string) { + fake.graceQuitTimeoutMutex.Lock() + defer fake.graceQuitTimeoutMutex.Unlock() + fake.GraceQuitTimeoutStub = stub +} + +func (fake *FakeEnvironment) GraceQuitTimeoutReturns(result1 string) { + fake.graceQuitTimeoutMutex.Lock() + defer fake.graceQuitTimeoutMutex.Unlock() + fake.GraceQuitTimeoutStub = nil + fake.graceQuitTimeoutReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) GraceQuitTimeoutReturnsOnCall(i int, result1 string) { + fake.graceQuitTimeoutMutex.Lock() + defer fake.graceQuitTimeoutMutex.Unlock() + fake.GraceQuitTimeoutStub = nil + if fake.graceQuitTimeoutReturnsOnCall == nil { + fake.graceQuitTimeoutReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.graceQuitTimeoutReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) HttpAPI() string { + fake.httpAPIMutex.Lock() + ret, specificReturn := fake.httpAPIReturnsOnCall[len(fake.httpAPIArgsForCall)] + fake.httpAPIArgsForCall = append(fake.httpAPIArgsForCall, struct { + }{}) + stub := fake.HttpAPIStub + fakeReturns := fake.httpAPIReturns + fake.recordInvocation("HttpAPI", []interface{}{}) + fake.httpAPIMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) HttpAPICallCount() int { + fake.httpAPIMutex.RLock() + defer fake.httpAPIMutex.RUnlock() + return len(fake.httpAPIArgsForCall) +} + +func (fake *FakeEnvironment) HttpAPICalls(stub func() string) { + fake.httpAPIMutex.Lock() + defer fake.httpAPIMutex.Unlock() + fake.HttpAPIStub = stub +} + +func (fake *FakeEnvironment) HttpAPIReturns(result1 string) { + fake.httpAPIMutex.Lock() + defer fake.httpAPIMutex.Unlock() + fake.HttpAPIStub = nil + fake.httpAPIReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) HttpAPIReturnsOnCall(i int, result1 string) { + fake.httpAPIMutex.Lock() + defer fake.httpAPIMutex.Unlock() + fake.HttpAPIStub = nil + if fake.httpAPIReturnsOnCall == nil { + fake.httpAPIReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.httpAPIReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) HttpServer() string { + fake.httpServerMutex.Lock() + ret, specificReturn := fake.httpServerReturnsOnCall[len(fake.httpServerArgsForCall)] + fake.httpServerArgsForCall = append(fake.httpServerArgsForCall, struct { + }{}) + stub := fake.HttpServerStub + fakeReturns := fake.httpServerReturns + fake.recordInvocation("HttpServer", []interface{}{}) + fake.httpServerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) HttpServerCallCount() int { + fake.httpServerMutex.RLock() + defer fake.httpServerMutex.RUnlock() + return len(fake.httpServerArgsForCall) +} + +func (fake *FakeEnvironment) HttpServerCalls(stub func() string) { + fake.httpServerMutex.Lock() + defer fake.httpServerMutex.Unlock() + fake.HttpServerStub = stub +} + +func (fake *FakeEnvironment) HttpServerReturns(result1 string) { + fake.httpServerMutex.Lock() + defer fake.httpServerMutex.Unlock() + fake.HttpServerStub = nil + fake.httpServerReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) HttpServerReturnsOnCall(i int, result1 string) { + fake.httpServerMutex.Lock() + defer fake.httpServerMutex.Unlock() + fake.HttpServerStub = nil + if fake.httpServerReturnsOnCall == nil { + fake.httpServerReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.httpServerReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) LoadBalancerType() string { + fake.loadBalancerTypeMutex.Lock() + ret, specificReturn := fake.loadBalancerTypeReturnsOnCall[len(fake.loadBalancerTypeArgsForCall)] + fake.loadBalancerTypeArgsForCall = append(fake.loadBalancerTypeArgsForCall, struct { + }{}) + stub := fake.LoadBalancerTypeStub + fakeReturns := fake.loadBalancerTypeReturns + fake.recordInvocation("LoadBalancerType", []interface{}{}) + fake.loadBalancerTypeMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) LoadBalancerTypeCallCount() int { + fake.loadBalancerTypeMutex.RLock() + defer fake.loadBalancerTypeMutex.RUnlock() + return len(fake.loadBalancerTypeArgsForCall) +} + +func (fake *FakeEnvironment) LoadBalancerTypeCalls(stub func() string) { + fake.loadBalancerTypeMutex.Lock() + defer fake.loadBalancerTypeMutex.Unlock() + fake.LoadBalancerTypeStub = stub +} + +func (fake *FakeEnvironment) LoadBalancerTypeReturns(result1 string) { + fake.loadBalancerTypeMutex.Lock() + defer fake.loadBalancerTypeMutex.Unlock() + fake.LoadBalancerTypeStub = nil + fake.loadBalancerTypeReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) LoadBalancerTypeReturnsOnCall(i int, result1 string) { + fake.loadBalancerTypeMutex.Lock() + defer fake.loadBalancerTypeMutex.Unlock() + fake.LoadBalancerTypeStub = nil + if fake.loadBalancerTypeReturnsOnCall == nil { + fake.loadBalancerTypeReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.loadBalancerTypeReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisDB() string { + fake.redisDBMutex.Lock() + ret, specificReturn := fake.redisDBReturnsOnCall[len(fake.redisDBArgsForCall)] + fake.redisDBArgsForCall = append(fake.redisDBArgsForCall, struct { + }{}) + stub := fake.RedisDBStub + fakeReturns := fake.redisDBReturns + fake.recordInvocation("RedisDB", []interface{}{}) + fake.redisDBMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) RedisDBCallCount() int { + fake.redisDBMutex.RLock() + defer fake.redisDBMutex.RUnlock() + return len(fake.redisDBArgsForCall) +} + +func (fake *FakeEnvironment) RedisDBCalls(stub func() string) { + fake.redisDBMutex.Lock() + defer fake.redisDBMutex.Unlock() + fake.RedisDBStub = stub +} + +func (fake *FakeEnvironment) RedisDBReturns(result1 string) { + fake.redisDBMutex.Lock() + defer fake.redisDBMutex.Unlock() + fake.RedisDBStub = nil + fake.redisDBReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisDBReturnsOnCall(i int, result1 string) { + fake.redisDBMutex.Lock() + defer fake.redisDBMutex.Unlock() + fake.RedisDBStub = nil + if fake.redisDBReturnsOnCall == nil { + fake.redisDBReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.redisDBReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisHost() string { + fake.redisHostMutex.Lock() + ret, specificReturn := fake.redisHostReturnsOnCall[len(fake.redisHostArgsForCall)] + fake.redisHostArgsForCall = append(fake.redisHostArgsForCall, struct { + }{}) + stub := fake.RedisHostStub + fakeReturns := fake.redisHostReturns + fake.recordInvocation("RedisHost", []interface{}{}) + fake.redisHostMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) RedisHostCallCount() int { + fake.redisHostMutex.RLock() + defer fake.redisHostMutex.RUnlock() + return len(fake.redisHostArgsForCall) +} + +func (fake *FakeEnvironment) RedisHostCalls(stub func() string) { + fake.redisHostMutex.Lock() + defer fake.redisHostMutex.Unlock() + fake.RedisHostStub = stub +} + +func (fake *FakeEnvironment) RedisHostReturns(result1 string) { + fake.redisHostMutex.Lock() + defer fake.redisHostMutex.Unlock() + fake.RedisHostStub = nil + fake.redisHostReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisHostReturnsOnCall(i int, result1 string) { + fake.redisHostMutex.Lock() + defer fake.redisHostMutex.Unlock() + fake.RedisHostStub = nil + if fake.redisHostReturnsOnCall == nil { + fake.redisHostReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.redisHostReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisPassword() string { + fake.redisPasswordMutex.Lock() + ret, specificReturn := fake.redisPasswordReturnsOnCall[len(fake.redisPasswordArgsForCall)] + fake.redisPasswordArgsForCall = append(fake.redisPasswordArgsForCall, struct { + }{}) + stub := fake.RedisPasswordStub + fakeReturns := fake.redisPasswordReturns + fake.recordInvocation("RedisPassword", []interface{}{}) + fake.redisPasswordMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) RedisPasswordCallCount() int { + fake.redisPasswordMutex.RLock() + defer fake.redisPasswordMutex.RUnlock() + return len(fake.redisPasswordArgsForCall) +} + +func (fake *FakeEnvironment) RedisPasswordCalls(stub func() string) { + fake.redisPasswordMutex.Lock() + defer fake.redisPasswordMutex.Unlock() + fake.RedisPasswordStub = stub +} + +func (fake *FakeEnvironment) RedisPasswordReturns(result1 string) { + fake.redisPasswordMutex.Lock() + defer fake.redisPasswordMutex.Unlock() + fake.RedisPasswordStub = nil + fake.redisPasswordReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisPasswordReturnsOnCall(i int, result1 string) { + fake.redisPasswordMutex.Lock() + defer fake.redisPasswordMutex.Unlock() + fake.RedisPasswordStub = nil + if fake.redisPasswordReturnsOnCall == nil { + fake.redisPasswordReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.redisPasswordReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisPort() string { + fake.redisPortMutex.Lock() + ret, specificReturn := fake.redisPortReturnsOnCall[len(fake.redisPortArgsForCall)] + fake.redisPortArgsForCall = append(fake.redisPortArgsForCall, struct { + }{}) + stub := fake.RedisPortStub + fakeReturns := fake.redisPortReturns + fake.recordInvocation("RedisPort", []interface{}{}) + fake.redisPortMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) RedisPortCallCount() int { + fake.redisPortMutex.RLock() + defer fake.redisPortMutex.RUnlock() + return len(fake.redisPortArgsForCall) +} + +func (fake *FakeEnvironment) RedisPortCalls(stub func() string) { + fake.redisPortMutex.Lock() + defer fake.redisPortMutex.Unlock() + fake.RedisPortStub = stub +} + +func (fake *FakeEnvironment) RedisPortReturns(result1 string) { + fake.redisPortMutex.Lock() + defer fake.redisPortMutex.Unlock() + fake.RedisPortStub = nil + fake.redisPortReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RedisPortReturnsOnCall(i int, result1 string) { + fake.redisPortMutex.Lock() + defer fake.redisPortMutex.Unlock() + fake.RedisPortStub = nil + if fake.redisPortReturnsOnCall == nil { + fake.redisPortReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.redisPortReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RtmpServer() string { + fake.rtmpServerMutex.Lock() + ret, specificReturn := fake.rtmpServerReturnsOnCall[len(fake.rtmpServerArgsForCall)] + fake.rtmpServerArgsForCall = append(fake.rtmpServerArgsForCall, struct { + }{}) + stub := fake.RtmpServerStub + fakeReturns := fake.rtmpServerReturns + fake.recordInvocation("RtmpServer", []interface{}{}) + fake.rtmpServerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) RtmpServerCallCount() int { + fake.rtmpServerMutex.RLock() + defer fake.rtmpServerMutex.RUnlock() + return len(fake.rtmpServerArgsForCall) +} + +func (fake *FakeEnvironment) RtmpServerCalls(stub func() string) { + fake.rtmpServerMutex.Lock() + defer fake.rtmpServerMutex.Unlock() + fake.RtmpServerStub = stub +} + +func (fake *FakeEnvironment) RtmpServerReturns(result1 string) { + fake.rtmpServerMutex.Lock() + defer fake.rtmpServerMutex.Unlock() + fake.RtmpServerStub = nil + fake.rtmpServerReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) RtmpServerReturnsOnCall(i int, result1 string) { + fake.rtmpServerMutex.Lock() + defer fake.rtmpServerMutex.Unlock() + fake.RtmpServerStub = nil + if fake.rtmpServerReturnsOnCall == nil { + fake.rtmpServerReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.rtmpServerReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) SRTServer() string { + fake.sRTServerMutex.Lock() + ret, specificReturn := fake.sRTServerReturnsOnCall[len(fake.sRTServerArgsForCall)] + fake.sRTServerArgsForCall = append(fake.sRTServerArgsForCall, struct { + }{}) + stub := fake.SRTServerStub + fakeReturns := fake.sRTServerReturns + fake.recordInvocation("SRTServer", []interface{}{}) + fake.sRTServerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) SRTServerCallCount() int { + fake.sRTServerMutex.RLock() + defer fake.sRTServerMutex.RUnlock() + return len(fake.sRTServerArgsForCall) +} + +func (fake *FakeEnvironment) SRTServerCalls(stub func() string) { + fake.sRTServerMutex.Lock() + defer fake.sRTServerMutex.Unlock() + fake.SRTServerStub = stub +} + +func (fake *FakeEnvironment) SRTServerReturns(result1 string) { + fake.sRTServerMutex.Lock() + defer fake.sRTServerMutex.Unlock() + fake.SRTServerStub = nil + fake.sRTServerReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) SRTServerReturnsOnCall(i int, result1 string) { + fake.sRTServerMutex.Lock() + defer fake.sRTServerMutex.Unlock() + fake.SRTServerStub = nil + if fake.sRTServerReturnsOnCall == nil { + fake.sRTServerReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.sRTServerReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) StaticFiles() string { + fake.staticFilesMutex.Lock() + ret, specificReturn := fake.staticFilesReturnsOnCall[len(fake.staticFilesArgsForCall)] + fake.staticFilesArgsForCall = append(fake.staticFilesArgsForCall, struct { + }{}) + stub := fake.StaticFilesStub + fakeReturns := fake.staticFilesReturns + fake.recordInvocation("StaticFiles", []interface{}{}) + fake.staticFilesMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) StaticFilesCallCount() int { + fake.staticFilesMutex.RLock() + defer fake.staticFilesMutex.RUnlock() + return len(fake.staticFilesArgsForCall) +} + +func (fake *FakeEnvironment) StaticFilesCalls(stub func() string) { + fake.staticFilesMutex.Lock() + defer fake.staticFilesMutex.Unlock() + fake.StaticFilesStub = stub +} + +func (fake *FakeEnvironment) StaticFilesReturns(result1 string) { + fake.staticFilesMutex.Lock() + defer fake.staticFilesMutex.Unlock() + fake.StaticFilesStub = nil + fake.staticFilesReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) StaticFilesReturnsOnCall(i int, result1 string) { + fake.staticFilesMutex.Lock() + defer fake.staticFilesMutex.Unlock() + fake.StaticFilesStub = nil + if fake.staticFilesReturnsOnCall == nil { + fake.staticFilesReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.staticFilesReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) SystemAPI() string { + fake.systemAPIMutex.Lock() + ret, specificReturn := fake.systemAPIReturnsOnCall[len(fake.systemAPIArgsForCall)] + fake.systemAPIArgsForCall = append(fake.systemAPIArgsForCall, struct { + }{}) + stub := fake.SystemAPIStub + fakeReturns := fake.systemAPIReturns + fake.recordInvocation("SystemAPI", []interface{}{}) + fake.systemAPIMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) SystemAPICallCount() int { + fake.systemAPIMutex.RLock() + defer fake.systemAPIMutex.RUnlock() + return len(fake.systemAPIArgsForCall) +} + +func (fake *FakeEnvironment) SystemAPICalls(stub func() string) { + fake.systemAPIMutex.Lock() + defer fake.systemAPIMutex.Unlock() + fake.SystemAPIStub = stub +} + +func (fake *FakeEnvironment) SystemAPIReturns(result1 string) { + fake.systemAPIMutex.Lock() + defer fake.systemAPIMutex.Unlock() + fake.SystemAPIStub = nil + fake.systemAPIReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) SystemAPIReturnsOnCall(i int, result1 string) { + fake.systemAPIMutex.Lock() + defer fake.systemAPIMutex.Unlock() + fake.SystemAPIStub = nil + if fake.systemAPIReturnsOnCall == nil { + fake.systemAPIReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.systemAPIReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) WebRTCServer() string { + fake.webRTCServerMutex.Lock() + ret, specificReturn := fake.webRTCServerReturnsOnCall[len(fake.webRTCServerArgsForCall)] + fake.webRTCServerArgsForCall = append(fake.webRTCServerArgsForCall, struct { + }{}) + stub := fake.WebRTCServerStub + fakeReturns := fake.webRTCServerReturns + fake.recordInvocation("WebRTCServer", []interface{}{}) + fake.webRTCServerMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeEnvironment) WebRTCServerCallCount() int { + fake.webRTCServerMutex.RLock() + defer fake.webRTCServerMutex.RUnlock() + return len(fake.webRTCServerArgsForCall) +} + +func (fake *FakeEnvironment) WebRTCServerCalls(stub func() string) { + fake.webRTCServerMutex.Lock() + defer fake.webRTCServerMutex.Unlock() + fake.WebRTCServerStub = stub +} + +func (fake *FakeEnvironment) WebRTCServerReturns(result1 string) { + fake.webRTCServerMutex.Lock() + defer fake.webRTCServerMutex.Unlock() + fake.WebRTCServerStub = nil + fake.webRTCServerReturns = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) WebRTCServerReturnsOnCall(i int, result1 string) { + fake.webRTCServerMutex.Lock() + defer fake.webRTCServerMutex.Unlock() + fake.WebRTCServerStub = nil + if fake.webRTCServerReturnsOnCall == nil { + fake.webRTCServerReturnsOnCall = make(map[int]struct { + result1 string + }) + } + fake.webRTCServerReturnsOnCall[i] = struct { + result1 string + }{result1} +} + +func (fake *FakeEnvironment) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeEnvironment) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ env.Environment = new(FakeEnvironment) diff --git a/internal/env/gen.go b/internal/env/gen.go new file mode 100644 index 000000000..107eee7d2 --- /dev/null +++ b/internal/env/gen.go @@ -0,0 +1,6 @@ +// Copyright (c) 2026 Winlin +// +// SPDX-License-Identifier: MIT +package env + +//go:generate go tool counterfeiter -o envfakes/fake_environment.go . Environment diff --git a/internal/version/version.go b/internal/version/version.go index 21b3267af..99de863b3 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -15,7 +15,7 @@ func VersionMinor() int { } func VersionRevision() int { - return 143 + return 144 } func Version() string { diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index e4c13ffd6..b3117fc16 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 7.0 Changelog +* v7.0, 2026-04-18, Merge [#4665](https://github.com/ossrs/srs/pull/4665): Proxy: Harden internal/env tests and add counterfeiter fake generation. v7.0.144 (#4665) * v7.0, 2026-04-12, Merge [#4661](https://github.com/ossrs/srs/pull/4661): Proxy: Move build output to bin/, replace godotenv with custom .env parser, and update docs. v7.0.143 (#4661) * v7.0, 2026-04-06, Merge [#4657](https://github.com/ossrs/srs/pull/4657): Proxy: Refactor bootstrap for multi-server support and rebrand to SRSX. v7.0.142 (#4657) * v7.0, 2026-03-26, Merge [#4654](https://github.com/ossrs/srs/pull/4654): OpenClaw: Restructure workspace with symlinks, add codebase map, and rewrite AI docs. v7.0.141 (#4654) diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index b8bd5cc73..12344c8e1 100644 --- a/trunk/src/core/srs_core_version7.hpp +++ b/trunk/src/core/srs_core_version7.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 7 #define VERSION_MINOR 0 -#define VERSION_REVISION 143 +#define VERSION_REVISION 144 #endif