//go:build !windows

package process

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"sync/atomic"
	"syscall"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/influxdata/telegraf/testutil"
)

// test that a restarting process resets pipes properly
func TestRestartingRebindsPipes(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping long running test in short mode")
	}

	exe, err := os.Executable()
	require.NoError(t, err)

	p, err := New([]string{exe, "-external"}, []string{"INTERNAL_PROCESS_MODE=application"})
	p.RestartDelay = 100 * time.Nanosecond
	p.Log = testutil.Logger{}
	require.NoError(t, err)

	linesRead := int64(0)
	p.ReadStdoutFn = func(r io.Reader) {
		scanner := bufio.NewScanner(r)

		for scanner.Scan() {
			atomic.AddInt64(&linesRead, 1)
		}
	}

	require.NoError(t, p.Start())

	for atomic.LoadInt64(&linesRead) < 1 {
		time.Sleep(1 * time.Millisecond)
	}

	require.NoError(t, syscall.Kill(p.Pid(), syscall.SIGKILL))

	for atomic.LoadInt64(&linesRead) < 2 {
		time.Sleep(1 * time.Millisecond)
	}

	// the mainLoopWg.Wait() call p.Stop() makes takes multiple seconds to complete
	p.Stop()
}

var external = flag.Bool("external", false,
	"if true, run externalProcess instead of tests")

func TestMain(m *testing.M) {
	flag.Parse()
	runMode := os.Getenv("INTERNAL_PROCESS_MODE")
	if *external && runMode == "application" {
		externalProcess()
		os.Exit(0)
	}
	code := m.Run()
	os.Exit(code)
}

// externalProcess is an external "misbehaving" process that won't exit
// cleanly.
func externalProcess() {
	wait := make(chan int)
	fmt.Fprintln(os.Stdout, "started")
	<-wait
	os.Exit(2) //nolint:revive // os.Exit called intentionally
}
