package media_test import ( "context" "fmt" "io" "os" "os/exec" "strconv" "strings" "testing" "git.netflux.io/rob/clipper/media" "github.com/stretchr/testify/require" "go.uber.org/zap" ) // fixtureReader loads a fixture into a ReadCloser with the provided limit. func fixtureReader(t *testing.T, fixturePath string, limit int64) io.ReadCloser { fptr, err := os.Open(fixturePath) require.NoError(t, err) // limitReader to make the mock work realistically, not intended for assertions: return struct { io.Reader io.Closer }{ Reader: io.LimitReader(fptr, limit), Closer: fptr, } } // helperCommand returns a function that builds an *exec.Cmd which executes a // test function in order to act as a mock process. func helperCommand(t *testing.T, wantCommand, stdoutFile, stderrString string, forceExitCode int) media.CommandFunc { return func(ctx context.Context, name string, args ...string) *exec.Cmd { cs := []string{"-test.run=TestHelperProcess", "--", name} cs = append(cs, args...) cmd := exec.CommandContext(ctx, os.Args[0], cs...) cmd.Env = []string{ "GO_WANT_HELPER_PROCESS=1", "GO_WANT_COMMAND=" + wantCommand, "GO_STDOUT_FILE=" + stdoutFile, "GO_STDERR_STRING=" + stderrString, "GO_FORCE_EXIT_CODE=" + strconv.Itoa(forceExitCode), } return cmd } } // TestHelperProcess is the body for the mock executable process built by // helperCommand. func TestHelperProcess(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { return } defer func() { // Stop the helper process writing to stdout after the test has finished. // This prevents it from writing the "PASS" string which is unwanted in // this context. if !t.Failed() { os.Stdout, _ = os.Open(os.DevNull) } }() if exitCode := os.Getenv("GO_FORCE_EXIT_CODE"); exitCode != "0" { c, _ := strconv.Atoi(exitCode) os.Stderr.WriteString(os.Getenv("GO_STDERR_STRING")) os.Exit(c) } if wantCommand := os.Getenv("GO_WANT_COMMAND"); wantCommand != "" { _, gotCmd, _ := strings.Cut(strings.Join(os.Args, " "), " -- ") if wantCommand != gotCmd { fmt.Fprintf(os.Stderr, "GO_WANT_COMMAND assertion failed:\nwant = %v\ngot = %v", wantCommand, gotCmd) t.Fail() // necessary to make the test fail } } // Copy stdin to /dev/null. This is required to avoid broken pipe errors in // the tests: _, err := io.Copy(io.Discard, os.Stdin) require.NoError(t, err) // If an output file is provided, then copy that to stdout: if fname := os.Getenv("GO_STDOUT_FILE"); fname != "" { fptr, err := os.Open(fname) require.NoError(t, err) defer fptr.Close() _, err = io.Copy(os.Stdout, fptr) require.NoError(t, err) } } // testLogger returns a functional development logger. //lint:ignore U1000 helper method func testLogger(t *testing.T) *zap.Logger { l, err := zap.NewDevelopment() require.NoError(t, err) return l }