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  }