src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/mods/unix/umask_test.go (about)

     1  //go:build unix
     2  
     3  package unix
     4  
     5  import (
     6  	"os"
     7  	"strconv"
     8  	"sync"
     9  	"testing"
    10  
    11  	"src.elv.sh/pkg/must"
    12  	"src.elv.sh/pkg/testutil"
    13  )
    14  
    15  func TestUmaskGetRace(t *testing.T) {
    16  	testutil.Umask(t, 0o22)
    17  	testutil.InTempDir(t)
    18  
    19  	// An old implementation of UmaskVariable.Get had a bug where it will
    20  	// briefly set the umask to 0, which can impact files created concurrently.
    21  	for i := 0; i < 100; i++ {
    22  		filename := strconv.Itoa(i)
    23  		runParallel(
    24  			func() {
    25  				// Calling UmaskVariable.Get is much quicker than creating a
    26  				// file, so do it in a loop to increase the chance of triggering
    27  				// a race condition.
    28  				for j := 0; j < 100; j++ {
    29  					UmaskVariable{}.Get()
    30  				}
    31  			},
    32  			func() {
    33  				must.OK(create(filename, 0o666))
    34  			})
    35  
    36  		perm := must.OK1(os.Stat(filename)).Mode().Perm()
    37  		if perm != 0o644 {
    38  			t.Errorf("got perm %o, want 0o644 (run %d)", perm, i)
    39  		}
    40  	}
    41  }
    42  
    43  func runParallel(funcs ...func()) {
    44  	var wg sync.WaitGroup
    45  	wg.Add(len(funcs))
    46  	for _, f := range funcs {
    47  		f := f
    48  		go func() {
    49  			f()
    50  			wg.Done()
    51  		}()
    52  	}
    53  	wg.Wait()
    54  }
    55  
    56  func create(name string, perm os.FileMode) error {
    57  	file, err := os.OpenFile(name, os.O_CREATE, perm)
    58  	if err == nil {
    59  		file.Close()
    60  	}
    61  	return err
    62  }