github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/libs/tempfile/tempfile_test.go (about) 1 package tempfile 2 3 // Need access to internal variables, so can't use _test package 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "os" 10 testing "testing" 11 12 "github.com/stretchr/testify/require" 13 14 tmrand "github.com/franono/tendermint/libs/rand" 15 ) 16 17 func TestWriteFileAtomic(t *testing.T) { 18 var ( 19 data = []byte(tmrand.Str(tmrand.Intn(2048))) 20 old = tmrand.Bytes(tmrand.Intn(2048)) 21 perm os.FileMode = 0600 22 ) 23 24 f, err := ioutil.TempFile("/tmp", "write-atomic-test-") 25 if err != nil { 26 t.Fatal(err) 27 } 28 defer os.Remove(f.Name()) 29 30 if err = ioutil.WriteFile(f.Name(), old, 0600); err != nil { 31 t.Fatal(err) 32 } 33 34 if err = WriteFileAtomic(f.Name(), data, perm); err != nil { 35 t.Fatal(err) 36 } 37 38 rData, err := ioutil.ReadFile(f.Name()) 39 if err != nil { 40 t.Fatal(err) 41 } 42 43 if !bytes.Equal(data, rData) { 44 t.Fatalf("data mismatch: %v != %v", data, rData) 45 } 46 47 stat, err := os.Stat(f.Name()) 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 if have, want := stat.Mode().Perm(), perm; have != want { 53 t.Errorf("have %v, want %v", have, want) 54 } 55 } 56 57 // This tests atomic write file when there is a single duplicate file. 58 // Expected behavior is for a new file to be created, and the original write file to be unaltered. 59 func TestWriteFileAtomicDuplicateFile(t *testing.T) { 60 var ( 61 defaultSeed uint64 = 1 62 testString = "This is a glorious test string" 63 expectedString = "Did the test file's string appear here?" 64 65 fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt" 66 ) 67 // Create a file at the seed, and reset the seed. 68 atomicWriteFileRand = defaultSeed 69 firstFileRand := randWriteFileSuffix() 70 atomicWriteFileRand = defaultSeed 71 fname := "/tmp/" + atomicWriteFilePrefix + firstFileRand 72 f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777) 73 defer os.Remove(fname) 74 // Defer here, in case there is a panic in WriteFileAtomic. 75 defer os.Remove(fileToWrite) 76 77 require.Nil(t, err) 78 f.WriteString(testString) 79 WriteFileAtomic(fileToWrite, []byte(expectedString), 0777) 80 // Check that the first atomic file was untouched 81 firstAtomicFileBytes, err := ioutil.ReadFile(fname) 82 require.Nil(t, err, "Error reading first atomic file") 83 require.Equal(t, []byte(testString), firstAtomicFileBytes, "First atomic file was overwritten") 84 // Check that the resultant file is correct 85 resultantFileBytes, err := ioutil.ReadFile(fileToWrite) 86 require.Nil(t, err, "Error reading resultant file") 87 require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes") 88 89 // Check that the intermediate write file was deleted 90 // Get the second write files' randomness 91 atomicWriteFileRand = defaultSeed 92 _ = randWriteFileSuffix() 93 secondFileRand := randWriteFileSuffix() 94 _, err = os.Stat("/tmp/" + atomicWriteFilePrefix + secondFileRand) 95 require.True(t, os.IsNotExist(err), "Intermittent atomic write file not deleted") 96 } 97 98 // This tests atomic write file when there are many duplicate files. 99 // Expected behavior is for a new file to be created under a completely new seed, 100 // and the original write files to be unaltered. 101 func TestWriteFileAtomicManyDuplicates(t *testing.T) { 102 var ( 103 defaultSeed uint64 = 2 104 testString = "This is a glorious test string, from file %d" 105 expectedString = "Did any of the test file's string appear here?" 106 107 fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt" 108 ) 109 // Initialize all of the atomic write files 110 atomicWriteFileRand = defaultSeed 111 for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ { 112 fileRand := randWriteFileSuffix() 113 fname := "/tmp/" + atomicWriteFilePrefix + fileRand 114 f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777) 115 require.Nil(t, err) 116 f.WriteString(fmt.Sprintf(testString, i)) 117 defer os.Remove(fname) 118 } 119 120 atomicWriteFileRand = defaultSeed 121 // Defer here, in case there is a panic in WriteFileAtomic. 122 defer os.Remove(fileToWrite) 123 124 WriteFileAtomic(fileToWrite, []byte(expectedString), 0777) 125 // Check that all intermittent atomic file were untouched 126 atomicWriteFileRand = defaultSeed 127 for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ { 128 fileRand := randWriteFileSuffix() 129 fname := "/tmp/" + atomicWriteFilePrefix + fileRand 130 firstAtomicFileBytes, err := ioutil.ReadFile(fname) 131 require.Nil(t, err, "Error reading first atomic file") 132 require.Equal(t, []byte(fmt.Sprintf(testString, i)), firstAtomicFileBytes, 133 "atomic write file %d was overwritten", i) 134 } 135 136 // Check that the resultant file is correct 137 resultantFileBytes, err := ioutil.ReadFile(fileToWrite) 138 require.Nil(t, err, "Error reading resultant file") 139 require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes") 140 }