diff --git a/cmd/opampsupervisor/go.mod b/cmd/opampsupervisor/go.mod index 24628524f45c3..79cba2b82b91a 100644 --- a/cmd/opampsupervisor/go.mod +++ b/cmd/opampsupervisor/go.mod @@ -97,6 +97,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter v0.135.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/syslogexporter v0.135.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.135.0 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.135.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.135.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/pdatautil v0.135.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/core/xidutils v0.135.0 // indirect diff --git a/exporter/prometheusremotewriteexporter/exporter_test.go b/exporter/prometheusremotewriteexporter/exporter_test.go index c948056150367..079b921cdd2ba 100644 --- a/exporter/prometheusremotewriteexporter/exporter_test.go +++ b/exporter/prometheusremotewriteexporter/exporter_test.go @@ -11,8 +11,6 @@ import ( "net/http" "net/http/httptest" "net/url" - "os" - "runtime" "strconv" "strings" "sync" @@ -759,18 +757,8 @@ func Test_PushMetrics(t *testing.T) { } if useWAL { - var dir string - if runtime.GOOS == "windows" { - // On Windows, use os.MkdirTemp to create directory since t.TempDir results in an error during cleanup in scoped-tests. - // See https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/42639 - var err error - dir, err = os.MkdirTemp("", tt.name) //nolint:usetesting - require.NoError(t, err) - } else { - dir = t.TempDir() - } cfg.WAL = configoptional.Some(WALConfig{ - Directory: dir, + Directory: testutil.TempDir(t), }) } diff --git a/internal/common/testutil/testutil.go b/internal/common/testutil/testutil.go index 823815fbb6c94..347a6f9718cb9 100644 --- a/internal/common/testutil/testutil.go +++ b/internal/common/testutil/testutil.go @@ -6,11 +6,14 @@ package testutil // import "github.com/open-telemetry/opentelemetry-collector-co import ( "fmt" "net" + "os" "os/exec" "runtime" "strconv" "strings" "testing" + "unicode" + "unicode/utf8" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -151,3 +154,53 @@ func GetAvailablePort(tb testing.TB) int { func EndpointForPort(port int) string { return fmt.Sprintf("localhost:%d", port) } + +// TempDir creates a temporary directory in a safe way. On Linux, it just calls tb.TempDir. +// +// On Windows, it uses os.MkdirTemp to create directory since t.TempDir results in an error during cleanup in scoped-tests, +// possibly due to an interaction with the -count argument in `go test`. It does not do any cleanup (i.e. the directory is left on the filesystem). +// Prefer using tb.TempDir directly if possible. +// +// See https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/42639 +func TempDir(tb testing.TB) string { + if runtime.GOOS == "windows" { + name := sanitizePattern(tb.Name()) + dir, err := os.MkdirTemp("", name) //nolint:usetesting + require.NoError(tb, err) + return dir + } + + return tb.TempDir() +} + +// sanitizePattern so that it works correctly with os.MkdirTemp. +// +// The following code is taken from the t.TempDir implementation. +// Copyright 2009 The Go Authors. All rights reserved. +// Taken from https://cs.opensource.google/go/go/+/refs/tags/go1.25.1:src/testing/testing.go;l=1340-1364;drc=49cdf0c42e320dfed044baa551610f081eafb781 +func sanitizePattern(pattern string) string { + // Limit length of file names on disk. + // Invalid runes from slicing are dropped by strings.Map below. + pattern = pattern[:min(len(pattern), 64)] + + // Drop unusual characters (such as path separators or + // characters interacting with globs) from the directory name to + // avoid surprising os.MkdirTemp behavior. + mapper := func(r rune) rune { + if r < utf8.RuneSelf { + const allowed = "!#$%&()+,-.=@^_{}~ " + if '0' <= r && r <= '9' || + 'a' <= r && r <= 'z' || + 'A' <= r && r <= 'Z' { + return r + } + if strings.ContainsRune(allowed, r) { + return r + } + } else if unicode.IsLetter(r) || unicode.IsNumber(r) { + return r + } + return -1 + } + return strings.Map(mapper, pattern) +} diff --git a/testbed/testbed/child_process_collector.go b/testbed/testbed/child_process_collector.go index 69cf64f56313e..90b02cfce2b04 100644 --- a/testbed/testbed/child_process_collector.go +++ b/testbed/testbed/child_process_collector.go @@ -24,6 +24,8 @@ import ( "github.com/shirou/gopsutil/v4/cpu" "github.com/shirou/gopsutil/v4/process" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" ) // childProcessCollector implements the OtelcolRunner interface as a child process on the same machine executing @@ -117,8 +119,9 @@ func (cp *childProcessCollector) PrepareConfig(t *testing.T, configStr string) ( configCleanup = func() { // NoOp } + var file *os.File - file, err = os.CreateTemp(t.TempDir(), "agent*.yaml") + file, err = os.CreateTemp(testutil.TempDir(t), "agent*.yaml") if err != nil { log.Printf("%s", err) return configCleanup, err diff --git a/testbed/testbed/in_process_collector.go b/testbed/testbed/in_process_collector.go index 058882b60847e..5aa22a23bfd29 100644 --- a/testbed/testbed/in_process_collector.go +++ b/testbed/testbed/in_process_collector.go @@ -19,6 +19,8 @@ import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/fileprovider" "go.opentelemetry.io/collector/otelcol" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" ) // inProcessCollector implements the OtelcolRunner interfaces running a single otelcol as a go routine within the @@ -51,8 +53,7 @@ func (ipp *inProcessCollector) PrepareConfig(t *testing.T, configStr string) (co func (ipp *inProcessCollector) Start(StartParams) error { var err error - - confFile, err := os.CreateTemp(ipp.t.TempDir(), "conf-") + confFile, err := os.CreateTemp(testutil.TempDir(ipp.t), "conf-") if err != nil { return err }