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