You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2026/07/06 18:53:46 UTC

(plc4x) 01/09: fix(plc4go): data race in testutils.shouldNoColor under parallel tests

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 65e1935300710c5a5c07c8ee72ca969382b0fafd
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Jul 3 09:39:50 2026 +0200

    fix(plc4go): data race in testutils.shouldNoColor under parallel tests
    
    shouldNoColor writes the global color.NoColor and is invoked by
    ProduceTestingLogger for every test - parallel subtests in consumers
    trip the race detector on the unsynchronized concurrent writes. The
    result only depends on the environment, so compute it exactly once.
---
 plc4go/spi/testutils/TestUtils.go | 47 +++++++++++++++++++++++++--------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/plc4go/spi/testutils/TestUtils.go b/plc4go/spi/testutils/TestUtils.go
index 9a7e18e960..868446585d 100644
--- a/plc4go/spi/testutils/TestUtils.go
+++ b/plc4go/spi/testutils/TestUtils.go
@@ -169,25 +169,38 @@ func getOrLeaveDuration(key string, setting *time.Duration) {
 	}
 }
 
+// shouldNoColor's result only depends on the environment, but it WRITES the
+// global color.NoColor - and it is called from ProduceTestingLogger for every
+// (potentially parallel) test, which the race detector flags as concurrent
+// unsynchronized writes. Compute it exactly once.
+var (
+	noColorOnce   sync.Once
+	noColorResult bool
+)
+
 func shouldNoColor() bool {
-	if _, forceColorEnv := os.LookupEnv("FORCE_COLOR"); forceColorEnv {
-		color.NoColor = false // Apparently the color.NoColor is a bit to eager
-		return false
-	}
-	noColor := false
-	{
-		_, noColorEnv := os.LookupEnv("NO_COLOR")
-		onJenkins := os.Getenv("JENKINS_URL") != ""
-		onGithubAction := os.Getenv("GITHUB_ACTIONS") != ""
-		onCI := os.Getenv("CI") != ""
-		if noColorEnv || onJenkins || onGithubAction || onCI {
-			noColor = true
+	noColorOnce.Do(func() {
+		if _, forceColorEnv := os.LookupEnv("FORCE_COLOR"); forceColorEnv {
+			color.NoColor = false // Apparently the color.NoColor is a bit to eager
+			noColorResult = false
+			return
 		}
-	}
-	if !noColor {
-		color.NoColor = false // Apparently the color.NoColor is a bit to eager
-	}
-	return noColor
+		noColor := false
+		{
+			_, noColorEnv := os.LookupEnv("NO_COLOR")
+			onJenkins := os.Getenv("JENKINS_URL") != ""
+			onGithubAction := os.Getenv("GITHUB_ACTIONS") != ""
+			onCI := os.Getenv("CI") != ""
+			if noColorEnv || onJenkins || onGithubAction || onCI {
+				noColor = true
+			}
+		}
+		if !noColor {
+			color.NoColor = false // Apparently the color.NoColor is a bit to eager
+		}
+		noColorResult = noColor
+	})
+	return noColorResult
 }
 
 type TestingLog interface {