@@ -3,11 +3,14 @@ package logger
33import (
44 "bytes"
55 "fmt"
6+ "io"
7+ "os"
68 "strings"
79 "testing"
810
911 tftesting "github.com/gruntwork-io/terratest/modules/testing"
1012 "github.com/stretchr/testify/assert"
13+ "github.com/stretchr/testify/require"
1114)
1215
1316func TestDoLog (t * testing.T ) {
@@ -52,3 +55,54 @@ func TestCustomLogger(t *testing.T) {
5255 assert .Equal (t , "log output 2" , c .logs [1 ])
5356 assert .Equal (t , "subtest log" , c .logs [2 ])
5457}
58+
59+ // TestLockedLog make sure that Log and Logf which use stdout are thread-safe
60+ func TestLockedLog (t * testing.T ) {
61+ // should not call t.Parallel() since we are modifying os.Stdout
62+ stdout := os .Stdout
63+ t .Cleanup (func () {
64+ os .Stdout = stdout
65+ })
66+
67+ data := []struct {
68+ name string
69+ fn func (* testing.T , string )
70+ }{
71+ {
72+ name : "Log" ,
73+ fn : func (t * testing.T , s string ) {
74+ Log (t , s )
75+ }},
76+ {
77+ name : "Logf" ,
78+ fn : func (t * testing.T , s string ) {
79+ Logf (t , "%s" , s )
80+ }},
81+ }
82+
83+ for _ , d := range data {
84+ mutexStdout .Lock ()
85+ str := "Logging something" + t .Name ()
86+
87+ r , w , _ := os .Pipe ()
88+ os .Stdout = w
89+ ch := make (chan struct {})
90+ go func () {
91+ d .fn (t , str )
92+ w .Close ()
93+ close (ch )
94+ }()
95+
96+ select {
97+ case <- ch :
98+ t .Error ("Log should be locked" )
99+ default :
100+ }
101+
102+ mutexStdout .Unlock ()
103+ b , err := io .ReadAll (r )
104+ require .NoError (t , err , "log should be unlocked" )
105+ assert .Contains (t , string (b ), str , "should contains logged string" )
106+ }
107+
108+ }
0 commit comments