diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7f35c98..acd7c81 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -37,11 +37,8 @@ jobs: version: "latest" install-go: false - - name: Go StaticCheck - run: go vet ./... - - name: Build run: go build -v ./... - name: Test - run: go test -v ./... + run: go test -race -v ./... diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml new file mode 100644 index 0000000..d28cacb --- /dev/null +++ b/.github/workflows/govulncheck.yml @@ -0,0 +1,39 @@ + +name: GoVulnCheck + +on: + push: + branches: [ "master", "main", $default-branch ] + pull_request: + branches: [ "master", "main", $default-branch ] + +permissions: + contents: read + +jobs: + govulncheck_job: + runs-on: ubuntu-latest + steps: + + - name: Harden Runner + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + with: + egress-policy: audit + + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - id: govulncheck + uses: golang/govulncheck-action@v1 + with: + go-package: ./... + output-format: sarif + output-file: results.sarif + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: results.sarif + # Optional category for the results + # Used to differentiate multiple results for one commit + category: govulncheck \ No newline at end of file diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 6dd3897..f987f7d 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -65,7 +65,7 @@ jobs: go-version: '1.22' - name: Testing... - run: go test -coverprofile cover.out -v ./... -json >tests.json + run: go test -race -coverprofile cover.out -v ./... -json >tests.json - name: GoLangCi-Lint... uses: golangci/golangci-lint-action@v6 diff --git a/tests/MainSupervisor.go b/tests/MainSupervisor.go index 08e4eff..0630a7a 100644 --- a/tests/MainSupervisor.go +++ b/tests/MainSupervisor.go @@ -1,11 +1,13 @@ package tests import ( + "context" "encoding/base64" "encoding/json" "fmt" "os" "os/exec" + "sync/atomic" "testing" "time" @@ -19,6 +21,7 @@ type MainSupervisor struct { testName string main MainFunc cmd *exec.Cmd + cancel atomic.Value } // Will init a new supervisor to execute the main function without crashing the current program. @@ -48,11 +51,9 @@ func NewMainSupervisor(t *testing.T, main MainFunc) *MainSupervisor { return supervisor } +// Run the main function in background, and return if it returns in the X first milliseconds. func (m *MainSupervisor) Run(config map[string]string) (string, bool, error) { var err error - if m.cmd != nil { - m.Close() - } addr, has := config["listen"] if !has { @@ -63,25 +64,25 @@ func (m *MainSupervisor) Run(config map[string]string) (string, bool, error) { config["listen"] = addr } - mainStarted := make(chan struct{}, 1) - mainStopped := make(chan struct{}, 2) + mainStopped := make(chan struct{}) - go func(config map[string]string, mainStarted, mainStopped chan<- struct{}) { - jsonArgs, err := json.Marshal(config) - if err != nil { - panic(err) - } - rawArgs := base64.RawStdEncoding.EncodeToString(jsonArgs) + jsonArgs, err := json.Marshal(config) + if err != nil { + panic(err) + } + rawArgs := base64.RawStdEncoding.EncodeToString(jsonArgs) - m.cmd = exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", m.testName)) + ctx, cancel := context.WithCancel(context.Background()) + m.ReplaceCancel(cancel) + + go func() { + m.cmd = exec.CommandContext(ctx, os.Args[0], fmt.Sprintf("-test.run=%s", m.testName)) m.cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", m.envName, rawArgs)) - close(mainStarted) - _ = m.cmd.Run() + m.cmd.Run() close(mainStopped) - }(config, mainStarted, mainStopped) + }() - <-mainStarted mainHasReturned := false select { case <-mainStopped: @@ -91,10 +92,19 @@ func (m *MainSupervisor) Run(config map[string]string) (string, bool, error) { return addr, mainHasReturned, nil } + +// Cancel the current main run func (m *MainSupervisor) Close() { - if m.cmd != nil && m.cmd.Process != nil { - _ = m.cmd.Process.Kill() - _, _ = m.cmd.Process.Wait() + m.ReplaceCancel(nil) +} + +// Cancel the current main run, if any, and set {cancel} instead +func (m *MainSupervisor) ReplaceCancel(cancel context.CancelFunc) { + oldCancel := m.cancel.Swap(cancel) + if oldCancel != nil { + oldCancelTyped := oldCancel.(context.CancelFunc) + if oldCancelTyped != nil { + oldCancelTyped() + } } - m.cmd = nil }