- package tempfile
-
- // Need access to internal variables, so can't use _test package
-
- import (
- "bytes"
- "fmt"
- mrand "math/rand"
- "os"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- tmrand "github.com/tendermint/tendermint/libs/rand"
- )
-
- func TestWriteFileAtomic(t *testing.T) {
- var (
- data = []byte(tmrand.Str(mrand.Intn(2048)))
- old = tmrand.Bytes(mrand.Intn(2048))
- perm os.FileMode = 0600
- )
-
- f, err := os.CreateTemp("/tmp", "write-atomic-test-")
- if err != nil {
- t.Fatal(err)
- }
- defer os.Remove(f.Name())
-
- if err = os.WriteFile(f.Name(), old, 0600); err != nil {
- t.Fatal(err)
- }
-
- if err = WriteFileAtomic(f.Name(), data, perm); err != nil {
- t.Fatal(err)
- }
-
- rData, err := os.ReadFile(f.Name())
- if err != nil {
- t.Fatal(err)
- }
-
- if !bytes.Equal(data, rData) {
- t.Fatalf("data mismatch: %v != %v", data, rData)
- }
-
- stat, err := os.Stat(f.Name())
- if err != nil {
- t.Fatal(err)
- }
-
- if have, want := stat.Mode().Perm(), perm; have != want {
- t.Errorf("have %v, want %v", have, want)
- }
- }
-
- // This tests atomic write file when there is a single duplicate file.
- // Expected behavior is for a new file to be created, and the original write file to be unaltered.
- func TestWriteFileAtomicDuplicateFile(t *testing.T) {
- var (
- defaultSeed uint64 = 1
- testString = "This is a glorious test string"
- expectedString = "Did the test file's string appear here?"
-
- fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt"
- )
- // Create a file at the seed, and reset the seed.
- atomicWriteFileRand = defaultSeed
- firstFileRand := randWriteFileSuffix()
- atomicWriteFileRand = defaultSeed
- fname := "/tmp/" + atomicWriteFilePrefix + firstFileRand
- f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777)
- defer os.Remove(fname)
- // Defer here, in case there is a panic in WriteFileAtomic.
- defer os.Remove(fileToWrite)
-
- require.NoError(t, err)
- _, err = f.WriteString(testString)
- require.NoError(t, err)
- err = WriteFileAtomic(fileToWrite, []byte(expectedString), 0777)
- require.NoError(t, err)
- // Check that the first atomic file was untouched
- firstAtomicFileBytes, err := os.ReadFile(fname)
- require.NoError(t, err, "Error reading first atomic file")
- require.Equal(t, []byte(testString), firstAtomicFileBytes, "First atomic file was overwritten")
- // Check that the resultant file is correct
- resultantFileBytes, err := os.ReadFile(fileToWrite)
- require.NoError(t, err, "Error reading resultant file")
- require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes")
-
- // Check that the intermediate write file was deleted
- // Get the second write files' randomness
- atomicWriteFileRand = defaultSeed
- _ = randWriteFileSuffix()
- secondFileRand := randWriteFileSuffix()
- _, err = os.Stat("/tmp/" + atomicWriteFilePrefix + secondFileRand)
- require.True(t, os.IsNotExist(err), "Intermittent atomic write file not deleted")
- }
-
- // This tests atomic write file when there are many duplicate files.
- // Expected behavior is for a new file to be created under a completely new seed,
- // and the original write files to be unaltered.
- func TestWriteFileAtomicManyDuplicates(t *testing.T) {
- var (
- defaultSeed uint64 = 2
- testString = "This is a glorious test string, from file %d"
- expectedString = "Did any of the test file's string appear here?"
-
- fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt"
- )
- // Initialize all of the atomic write files
- atomicWriteFileRand = defaultSeed
- for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ {
- fileRand := randWriteFileSuffix()
- fname := "/tmp/" + atomicWriteFilePrefix + fileRand
- f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777)
- require.Nil(t, err)
- _, err = f.WriteString(fmt.Sprintf(testString, i))
- require.NoError(t, err)
- defer os.Remove(fname)
- }
-
- atomicWriteFileRand = defaultSeed
- // Defer here, in case there is a panic in WriteFileAtomic.
- defer os.Remove(fileToWrite)
-
- err := WriteFileAtomic(fileToWrite, []byte(expectedString), 0777)
- require.NoError(t, err)
- // Check that all intermittent atomic file were untouched
- atomicWriteFileRand = defaultSeed
- for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ {
- fileRand := randWriteFileSuffix()
- fname := "/tmp/" + atomicWriteFilePrefix + fileRand
- firstAtomicFileBytes, err := os.ReadFile(fname)
- require.Nil(t, err, "Error reading first atomic file")
- require.Equal(t, []byte(fmt.Sprintf(testString, i)), firstAtomicFileBytes,
- "atomic write file %d was overwritten", i)
- }
-
- // Check that the resultant file is correct
- resultantFileBytes, err := os.ReadFile(fileToWrite)
- require.Nil(t, err, "Error reading resultant file")
- require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes")
- }
|