github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/fuse/ipns/ipns_test.go (about) 1 // +build !nofuse 2 3 package ipns 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 mrand "math/rand" 10 "os" 11 "sync" 12 "testing" 13 14 fstest "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" 15 racedet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" 16 17 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 18 core "github.com/ipfs/go-ipfs/core" 19 coremock "github.com/ipfs/go-ipfs/core/mock" 20 nsfs "github.com/ipfs/go-ipfs/ipnsfs" 21 u "github.com/ipfs/go-ipfs/util" 22 ci "github.com/ipfs/go-ipfs/util/testutil/ci" 23 ) 24 25 func maybeSkipFuseTests(t *testing.T) { 26 if ci.NoFuse() { 27 t.Skip("Skipping FUSE tests") 28 } 29 } 30 31 func randBytes(size int) []byte { 32 b := make([]byte, size) 33 u.NewTimeSeededRand().Read(b) 34 return b 35 } 36 37 func mkdir(t *testing.T, path string) { 38 err := os.Mkdir(path, os.ModeDir) 39 if err != nil { 40 t.Fatal(err) 41 } 42 } 43 44 func writeFile(t *testing.T, size int, path string) []byte { 45 return writeFileData(t, randBytes(size), path) 46 } 47 48 func writeFileData(t *testing.T, data []byte, path string) []byte { 49 fi, err := os.Create(path) 50 if err != nil { 51 t.Fatal(err) 52 } 53 54 n, err := fi.Write(data) 55 if err != nil { 56 t.Fatal(err) 57 } 58 59 if n != len(data) { 60 t.Fatal("Didnt write proper amount!") 61 } 62 63 err = fi.Close() 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 return data 69 } 70 71 func verifyFile(t *testing.T, path string, wantData []byte) { 72 isData, err := ioutil.ReadFile(path) 73 if err != nil { 74 t.Fatal(err) 75 } 76 if len(isData) != len(wantData) { 77 t.Fatal("Data not equal - length check failed") 78 } 79 if !bytes.Equal(isData, wantData) { 80 t.Fatal("Data not equal") 81 } 82 } 83 84 func checkExists(t *testing.T, path string) { 85 _, err := os.Stat(path) 86 if err != nil { 87 t.Fatal(err) 88 } 89 } 90 91 func closeMount(mnt *fstest.Mount) { 92 if err := recover(); err != nil { 93 log.Error("Recovered panic") 94 log.Error(err) 95 } 96 mnt.Close() 97 } 98 99 func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.Mount) { 100 maybeSkipFuseTests(t) 101 102 var err error 103 if node == nil { 104 node, err = coremock.NewMockNode() 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 ipnsfs, err := nsfs.NewFilesystem(context.Background(), node.DAG, node.Namesys, node.Pinning, node.PrivateKey) 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 node.IpnsFs = ipnsfs 115 } 116 117 fs, err := NewFileSystem(node, node.PrivateKey, "", "") 118 if err != nil { 119 t.Fatal(err) 120 } 121 mnt, err := fstest.MountedT(t, fs) 122 if err != nil { 123 t.Fatal(err) 124 } 125 126 return node, mnt 127 } 128 129 func TestIpnsLocalLink(t *testing.T) { 130 nd, mnt := setupIpnsTest(t, nil) 131 defer mnt.Close() 132 name := mnt.Dir + "/local" 133 134 _, err := os.Stat(name) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 linksto, err := os.Readlink(name) 140 if err != nil { 141 t.Fatal(err) 142 } 143 144 if linksto != nd.Identity.Pretty() { 145 t.Fatal("Link invalid") 146 } 147 } 148 149 // Test writing a file and reading it back 150 func TestIpnsBasicIO(t *testing.T) { 151 if testing.Short() { 152 t.SkipNow() 153 } 154 _, mnt := setupIpnsTest(t, nil) 155 defer closeMount(mnt) 156 157 fname := mnt.Dir + "/local/testfile" 158 data := writeFile(t, 10, fname) 159 160 rbuf, err := ioutil.ReadFile(fname) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 if !bytes.Equal(rbuf, data) { 166 t.Fatal("Incorrect Read!") 167 } 168 } 169 170 // Test to make sure file changes persist over mounts of ipns 171 func TestFilePersistence(t *testing.T) { 172 if testing.Short() { 173 t.SkipNow() 174 } 175 node, mnt := setupIpnsTest(t, nil) 176 177 fname := "/local/atestfile" 178 data := writeFile(t, 127, mnt.Dir+fname) 179 180 mnt.Close() 181 182 t.Log("Closed, opening new fs") 183 node, mnt = setupIpnsTest(t, node) 184 defer mnt.Close() 185 186 rbuf, err := ioutil.ReadFile(mnt.Dir + fname) 187 if err != nil { 188 t.Fatal(err) 189 } 190 191 if !bytes.Equal(rbuf, data) { 192 t.Fatalf("File data changed between mounts! sizes differ: %d != %d", len(data), len(rbuf)) 193 } 194 } 195 196 func TestMultipleDirs(t *testing.T) { 197 node, mnt := setupIpnsTest(t, nil) 198 199 t.Log("make a top level dir") 200 dir1 := "/local/test1" 201 mkdir(t, mnt.Dir+dir1) 202 203 checkExists(t, mnt.Dir+dir1) 204 205 t.Log("write a file in it") 206 data1 := writeFile(t, 4000, mnt.Dir+dir1+"/file1") 207 208 verifyFile(t, mnt.Dir+dir1+"/file1", data1) 209 210 t.Log("sub directory") 211 mkdir(t, mnt.Dir+dir1+"/dir2") 212 213 checkExists(t, mnt.Dir+dir1+"/dir2") 214 215 t.Log("file in that subdirectory") 216 data2 := writeFile(t, 5000, mnt.Dir+dir1+"/dir2/file2") 217 218 verifyFile(t, mnt.Dir+dir1+"/dir2/file2", data2) 219 220 mnt.Close() 221 t.Log("closing mount, then restarting") 222 223 _, mnt = setupIpnsTest(t, node) 224 225 checkExists(t, mnt.Dir+dir1) 226 227 verifyFile(t, mnt.Dir+dir1+"/file1", data1) 228 229 verifyFile(t, mnt.Dir+dir1+"/dir2/file2", data2) 230 mnt.Close() 231 } 232 233 // Test to make sure the filesystem reports file sizes correctly 234 func TestFileSizeReporting(t *testing.T) { 235 if testing.Short() { 236 t.SkipNow() 237 } 238 _, mnt := setupIpnsTest(t, nil) 239 defer mnt.Close() 240 241 fname := mnt.Dir + "/local/sizecheck" 242 data := writeFile(t, 5555, fname) 243 244 finfo, err := os.Stat(fname) 245 if err != nil { 246 t.Fatal(err) 247 } 248 249 if finfo.Size() != int64(len(data)) { 250 t.Fatal("Read incorrect size from stat!") 251 } 252 } 253 254 // Test to make sure you cant create multiple entries with the same name 255 func TestDoubleEntryFailure(t *testing.T) { 256 if testing.Short() { 257 t.SkipNow() 258 } 259 _, mnt := setupIpnsTest(t, nil) 260 defer mnt.Close() 261 262 dname := mnt.Dir + "/local/thisisadir" 263 err := os.Mkdir(dname, 0777) 264 if err != nil { 265 t.Fatal(err) 266 } 267 268 err = os.Mkdir(dname, 0777) 269 if err == nil { 270 t.Fatal("Should have gotten error one creating new directory.") 271 } 272 } 273 274 func TestAppendFile(t *testing.T) { 275 if testing.Short() { 276 t.SkipNow() 277 } 278 _, mnt := setupIpnsTest(t, nil) 279 defer mnt.Close() 280 281 fname := mnt.Dir + "/local/file" 282 data := writeFile(t, 1300, fname) 283 284 fi, err := os.OpenFile(fname, os.O_RDWR|os.O_APPEND, 0666) 285 if err != nil { 286 t.Fatal(err) 287 } 288 289 nudata := randBytes(500) 290 291 n, err := fi.Write(nudata) 292 if err != nil { 293 t.Fatal(err) 294 } 295 err = fi.Close() 296 if err != nil { 297 t.Fatal(err) 298 } 299 300 if n != len(nudata) { 301 t.Fatal("Failed to write enough bytes.") 302 } 303 304 data = append(data, nudata...) 305 306 rbuf, err := ioutil.ReadFile(fname) 307 if err != nil { 308 t.Fatal(err) 309 } 310 if !bytes.Equal(rbuf, data) { 311 t.Fatal("Data inconsistent!") 312 } 313 } 314 315 func TestConcurrentWrites(t *testing.T) { 316 if testing.Short() { 317 t.SkipNow() 318 } 319 _, mnt := setupIpnsTest(t, nil) 320 defer mnt.Close() 321 322 nactors := 4 323 filesPerActor := 400 324 fileSize := 2000 325 326 data := make([][][]byte, nactors) 327 328 if racedet.WithRace() { 329 nactors = 2 330 filesPerActor = 50 331 } 332 333 wg := sync.WaitGroup{} 334 for i := 0; i < nactors; i++ { 335 data[i] = make([][]byte, filesPerActor) 336 wg.Add(1) 337 go func(n int) { 338 defer wg.Done() 339 for j := 0; j < filesPerActor; j++ { 340 out := writeFile(t, fileSize, mnt.Dir+fmt.Sprintf("/local/%dFILE%d", n, j)) 341 data[n][j] = out 342 } 343 }(i) 344 } 345 wg.Wait() 346 347 for i := 0; i < nactors; i++ { 348 for j := 0; j < filesPerActor; j++ { 349 verifyFile(t, mnt.Dir+fmt.Sprintf("/local/%dFILE%d", i, j), data[i][j]) 350 } 351 } 352 } 353 354 func TestFSThrash(t *testing.T) { 355 files := make(map[string][]byte) 356 357 if testing.Short() { 358 t.SkipNow() 359 } 360 _, mnt := setupIpnsTest(t, nil) 361 defer mnt.Close() 362 363 base := mnt.Dir + "/local" 364 dirs := []string{base} 365 dirlock := sync.RWMutex{} 366 filelock := sync.Mutex{} 367 368 ndirWorkers := 2 369 nfileWorkers := 2 370 371 ndirs := 100 372 nfiles := 200 373 374 wg := sync.WaitGroup{} 375 376 // Spawn off workers to make directories 377 for i := 0; i < ndirWorkers; i++ { 378 wg.Add(1) 379 go func(worker int) { 380 defer wg.Done() 381 for j := 0; j < ndirs; j++ { 382 dirlock.RLock() 383 n := mrand.Intn(len(dirs)) 384 dir := dirs[n] 385 dirlock.RUnlock() 386 387 newDir := fmt.Sprintf("%s/dir%d-%d", dir, worker, j) 388 err := os.Mkdir(newDir, os.ModeDir) 389 if err != nil { 390 t.Fatal(err) 391 } 392 dirlock.Lock() 393 dirs = append(dirs, newDir) 394 dirlock.Unlock() 395 } 396 }(i) 397 } 398 399 // Spawn off workers to make files 400 for i := 0; i < nfileWorkers; i++ { 401 wg.Add(1) 402 go func(worker int) { 403 defer wg.Done() 404 for j := 0; j < nfiles; j++ { 405 dirlock.RLock() 406 n := mrand.Intn(len(dirs)) 407 dir := dirs[n] 408 dirlock.RUnlock() 409 410 newFileName := fmt.Sprintf("%s/file%d-%d", dir, worker, j) 411 412 data := writeFile(t, 2000+mrand.Intn(5000), newFileName) 413 filelock.Lock() 414 files[newFileName] = data 415 filelock.Unlock() 416 } 417 }(i) 418 } 419 420 wg.Wait() 421 for name, data := range files { 422 out, err := ioutil.ReadFile(name) 423 if err != nil { 424 t.Fatal(err) 425 } 426 427 if !bytes.Equal(data, out) { 428 t.Fatal("Data didnt match") 429 } 430 } 431 } 432 433 /* 434 func TestFastRepublish(t *testing.T) { 435 if testing.Short() { 436 t.SkipNow() 437 } 438 439 // make timeout noticeable. 440 osrt := shortRepublishTimeout 441 shortRepublishTimeout = time.Millisecond * 100 442 443 olrt := longRepublishTimeout 444 longRepublishTimeout = time.Second 445 446 node, mnt := setupIpnsTest(t, nil) 447 448 h, err := node.PrivateKey.GetPublic().Hash() 449 if err != nil { 450 t.Fatal(err) 451 } 452 pubkeyPath := "/ipns/" + u.Key(h).String() 453 454 // set them back 455 defer func() { 456 shortRepublishTimeout = osrt 457 longRepublishTimeout = olrt 458 mnt.Close() 459 }() 460 461 closed := make(chan struct{}) 462 dataA := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 463 dataB := []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") 464 465 fname := mnt.Dir + "/local/file" 466 467 // get first resolved hash 468 log.Debug("publishing first hash") 469 writeFileData(t, dataA, fname) // random 470 <-time.After(shortRepublishTimeout * 2) 471 log.Debug("resolving first hash") 472 resolvedHash, err := node.Namesys.Resolve(context.Background(), pubkeyPath) 473 if err != nil { 474 t.Fatal("resolve err:", pubkeyPath, err) 475 } 476 477 // constantly keep writing to the file 478 go func(timeout time.Duration) { 479 for { 480 select { 481 case <-closed: 482 return 483 484 case <-time.After(timeout * 8 / 10): 485 writeFileData(t, dataB, fname) 486 } 487 } 488 }(shortRepublishTimeout) 489 490 hasPublished := func() bool { 491 res, err := node.Namesys.Resolve(context.Background(), pubkeyPath) 492 if err != nil { 493 t.Fatalf("resolve err: %v", err) 494 } 495 return res != resolvedHash 496 } 497 498 // test things 499 500 // at this point, should not have written dataA and not have written dataB 501 rbuf, err := ioutil.ReadFile(fname) 502 if err != nil || !bytes.Equal(rbuf, dataA) { 503 t.Fatalf("Data inconsistent! %v %v", err, string(rbuf)) 504 } 505 506 if hasPublished() { 507 t.Fatal("published (wrote)") 508 } 509 510 <-time.After(shortRepublishTimeout * 11 / 10) 511 512 // at this point, should have written written dataB, but not published it 513 rbuf, err = ioutil.ReadFile(fname) 514 if err != nil || !bytes.Equal(rbuf, dataB) { 515 t.Fatalf("Data inconsistent! %v %v", err, string(rbuf)) 516 } 517 518 if hasPublished() { 519 t.Fatal("published (wrote)") 520 } 521 522 <-time.After(longRepublishTimeout * 11 / 10) 523 524 // at this point, should have written written dataB, and published it 525 rbuf, err = ioutil.ReadFile(fname) 526 if err != nil || !bytes.Equal(rbuf, dataB) { 527 t.Fatalf("Data inconsistent! %v %v", err, string(rbuf)) 528 } 529 530 if !hasPublished() { 531 t.Fatal("not published") 532 } 533 534 close(closed) 535 } 536 */ 537 538 // Test writing a medium sized file one byte at a time 539 func TestMultiWrite(t *testing.T) { 540 541 if testing.Short() { 542 t.SkipNow() 543 } 544 545 _, mnt := setupIpnsTest(t, nil) 546 defer mnt.Close() 547 548 fpath := mnt.Dir + "/local/file" 549 fi, err := os.Create(fpath) 550 if err != nil { 551 t.Fatal(err) 552 } 553 554 data := randBytes(1001) 555 for i := 0; i < len(data); i++ { 556 n, err := fi.Write(data[i : i+1]) 557 if err != nil { 558 t.Fatal(err) 559 } 560 if n != 1 { 561 t.Fatal("Somehow wrote the wrong number of bytes! (n != 1)") 562 } 563 } 564 fi.Close() 565 566 rbuf, err := ioutil.ReadFile(fpath) 567 if err != nil { 568 t.Fatal(err) 569 } 570 571 if !bytes.Equal(rbuf, data) { 572 t.Fatal("File on disk did not match bytes written") 573 } 574 }