github.com/decred/politeia@v1.4.0/politeiad/backend/gitbe/journal_test.go (about) 1 // Copyright (c) 2017-2020 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package gitbe 6 7 import ( 8 "errors" 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 "testing" 14 15 "golang.org/x/sync/errgroup" 16 ) 17 18 func testExact(j *Journal, filename string, count int) error { 19 // Test replay exact 20 err := j.Open(filename) 21 if err != nil { 22 return err 23 } 24 i := 0 25 for ; ; i++ { 26 err = j.Replay(filename, func(s string) error { 27 ss := fmt.Sprintf("%v", i) 28 if ss != s { 29 return fmt.Errorf("not equal: %v %v", ss, s) 30 } 31 return nil 32 }) 33 if errors.Is(err, io.EOF) { 34 if i > count { 35 return fmt.Errorf("ran too many times") 36 } 37 break 38 } else if err != nil { 39 return err 40 } 41 } 42 if i != count { 43 return fmt.Errorf("invalid count: %v %v", i, count) 44 } 45 46 return nil 47 } 48 49 func TestJournalExact(t *testing.T) { 50 dir, err := os.MkdirTemp("", "journal") 51 t.Logf("TestJournalExact: %v", dir) 52 if err != nil { 53 t.Fatal(err) 54 } 55 j := NewJournal() 56 57 // Test journal 58 count := 1000 59 filename := filepath.Join(dir, "file1") 60 for i := 0; i < count; i++ { 61 err = j.Journal(filename, fmt.Sprintf("%v", i)) 62 if err != nil { 63 t.Fatalf("%v: %v", i, err) 64 } 65 } 66 67 err = testExact(j, filename, count) 68 if err != nil { 69 t.Fatal(err) 70 } 71 72 err = j.Close(filename) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 os.RemoveAll(dir) 78 } 79 80 func TestJournalDoubleOpen(t *testing.T) { 81 dir, err := os.MkdirTemp("", "journal") 82 if err != nil { 83 t.Fatal(err) 84 } 85 t.Logf("TestJournalDoubleOpen: %v", dir) 86 87 j := NewJournal() 88 filename := filepath.Join(dir, "file1") 89 err = j.Journal(filename, "journal this") 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 err = j.Open(filename) 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 err = j.Open(filename) 100 if !errors.Is(err, ErrBusy) { 101 t.Fatal(err) 102 } 103 104 os.RemoveAll(dir) 105 } 106 107 func TestJournalDoubleClose(t *testing.T) { 108 dir, err := os.MkdirTemp("", "journal") 109 if err != nil { 110 t.Fatal(err) 111 } 112 t.Logf("TestJournalDoubleClose: %v", dir) 113 114 j := NewJournal() 115 filename := filepath.Join(dir, "file1") 116 err = j.Journal(filename, "journal this") 117 if err != nil { 118 t.Fatal(err) 119 } 120 121 err = j.Open(filename) 122 if err != nil { 123 t.Fatal(err) 124 } 125 126 err = j.Close(filename) 127 if err != nil { 128 t.Fatal(err) 129 } 130 131 err = j.Close(filename) 132 if !errors.Is(err, ErrNotFound) { 133 t.Fatal(err) 134 } 135 136 os.RemoveAll(dir) 137 } 138 139 func TestJournalConcurrent(t *testing.T) { 140 dir, err := os.MkdirTemp("", "journal") 141 t.Logf("TestJournalConcurrent: %v", dir) 142 if err != nil { 143 t.Fatal(err) 144 } 145 146 j := NewJournal() 147 // Test concurrent writes 148 files := 10 149 count := 1000 150 var eg errgroup.Group 151 for i := 0; i < files; i++ { 152 k := i 153 eg.Go(func() error { 154 filename := filepath.Join(dir, fmt.Sprintf("file%v", k)) 155 for k := 0; k < count; k++ { 156 err := j.Journal(filename, fmt.Sprintf("%v", k)) 157 if err != nil { 158 return err 159 } 160 } 161 return nil 162 }) 163 } 164 if err := eg.Wait(); err != nil { 165 t.Fatal(err) 166 } 167 168 // Test concurrent reads 169 t.Logf("TestJournalConcurrent: reading back %v", dir) 170 for i := 0; i < files; i++ { 171 k := i 172 eg.Go(func() error { 173 filename := filepath.Join(dir, fmt.Sprintf("file%v", k)) 174 return testExact(j, filename, count) 175 }) 176 } 177 if err := eg.Wait(); err != nil { 178 t.Fatal(err) 179 } 180 181 // Close concurrent 182 t.Logf("TestJournalConcurrent: closing %v", dir) 183 for i := 0; i < files; i++ { 184 k := i 185 eg.Go(func() error { 186 filename := filepath.Join(dir, fmt.Sprintf("file%v", k)) 187 return j.Close(filename) 188 }) 189 } 190 if err := eg.Wait(); err != nil { 191 t.Fatal(err) 192 } 193 194 os.RemoveAll(dir) 195 } 196 197 func TestJournalConcurrentSame(t *testing.T) { 198 dir, err := os.MkdirTemp("", "journal") 199 t.Logf("TestJournalConcurrentSame: %v", dir) 200 if err != nil { 201 t.Fatal(err) 202 } 203 204 j := NewJournal() 205 206 count := 10000 207 check := make(map[int]struct{}) 208 var eg errgroup.Group 209 filename := filepath.Join(dir, "file1") 210 for i := 0; i < count; i++ { 211 check[i] = struct{}{} 212 k := i 213 eg.Go(func() error { 214 return j.Journal(filename, fmt.Sprintf("%v", k)) 215 }) 216 } 217 if err := eg.Wait(); err != nil { 218 t.Fatal(err) 219 } 220 221 // Read back and make sure all entries exist 222 err = j.Open(filename) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 i := 0 228 for ; ; i++ { 229 err = j.Replay(filename, func(s string) error { 230 delete(check, i) 231 return nil 232 }) 233 if errors.Is(err, io.EOF) { 234 if i > count { 235 t.Fatalf("ran too many times") 236 } 237 break 238 } else if err != nil { 239 t.Fatal(err) 240 } 241 } 242 if i != count { 243 t.Fatalf("invalid count: %v %v", i, count) 244 } 245 if len(check) != 0 { 246 t.Fatalf("len != 0") 247 } 248 249 os.RemoveAll(dir) 250 } 251 252 func TestJournalCopy(t *testing.T) { 253 dir, err := os.MkdirTemp("", "journal") 254 t.Logf("TestJournalConcurrentCopy: %v", dir) 255 if err != nil { 256 t.Fatal(err) 257 } 258 259 j := NewJournal() 260 261 // Test journal 262 count := 1000 263 filename := filepath.Join(dir, "file1") 264 for i := 0; i < count; i++ { 265 err = j.Journal(filename, fmt.Sprintf("%v", i)) 266 if err != nil { 267 t.Fatalf("%v: %v", i, err) 268 } 269 } 270 271 err = testExact(j, filename, count) 272 if err != nil { 273 t.Fatal(err) 274 } 275 276 err = j.Close(filename) 277 if err != nil { 278 t.Fatal(err) 279 } 280 281 // Copy journal fail 282 destination := filepath.Join(dir, "") // Try to overwrite dir 283 err = j.Copy(filename, destination) 284 if err == nil { 285 t.Fatalf("Expected error") 286 } 287 288 // Copy journal fail 2 289 destination = filepath.Join(dir, "d", "..", "file1") // Try to overwrite same file 290 err = j.Copy(filename, destination) 291 if !errors.Is(err, ErrSameFile) { 292 t.Fatalf("Expected ErrSameFile") 293 } 294 295 // Copy journal 296 destination = filepath.Join(dir, "file2") 297 err = j.Copy(filename, destination) 298 if err != nil { 299 t.Fatal(err) 300 } 301 302 // Test Copy 303 err = testExact(j, destination, count) 304 if err != nil { 305 t.Fatal(err) 306 } 307 308 os.RemoveAll(dir) 309 }