github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/fuse/readonly/ipfs_test.go (about) 1 // +build !nofuse 2 3 package readonly 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "math/rand" 10 "os" 11 "path" 12 "sync" 13 "testing" 14 15 fstest "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" 16 17 key "github.com/ipfs/go-ipfs/blocks/key" 18 core "github.com/ipfs/go-ipfs/core" 19 coreunix "github.com/ipfs/go-ipfs/core/coreunix" 20 coremock "github.com/ipfs/go-ipfs/core/mock" 21 importer "github.com/ipfs/go-ipfs/importer" 22 chunk "github.com/ipfs/go-ipfs/importer/chunk" 23 dag "github.com/ipfs/go-ipfs/merkledag" 24 uio "github.com/ipfs/go-ipfs/unixfs/io" 25 u "github.com/ipfs/go-ipfs/util" 26 ci "github.com/ipfs/go-ipfs/util/testutil/ci" 27 ) 28 29 func maybeSkipFuseTests(t *testing.T) { 30 if ci.NoFuse() { 31 t.Skip("Skipping FUSE tests") 32 } 33 } 34 35 func randObj(t *testing.T, nd *core.IpfsNode, size int64) (*dag.Node, []byte) { 36 buf := make([]byte, size) 37 u.NewTimeSeededRand().Read(buf) 38 read := bytes.NewReader(buf) 39 obj, err := importer.BuildTrickleDagFromReader(nd.DAG, chunk.DefaultSplitter(read), nil) 40 if err != nil { 41 t.Fatal(err) 42 } 43 44 return obj, buf 45 } 46 47 func setupIpfsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.Mount) { 48 maybeSkipFuseTests(t) 49 50 var err error 51 if node == nil { 52 node, err = coremock.NewMockNode() 53 if err != nil { 54 t.Fatal(err) 55 } 56 } 57 58 fs := NewFileSystem(node) 59 mnt, err := fstest.MountedT(t, fs) 60 if err != nil { 61 t.Fatal(err) 62 } 63 64 return node, mnt 65 } 66 67 // Test writing an object and reading it back through fuse 68 func TestIpfsBasicRead(t *testing.T) { 69 if testing.Short() { 70 t.SkipNow() 71 } 72 nd, mnt := setupIpfsTest(t, nil) 73 defer mnt.Close() 74 75 fi, data := randObj(t, nd, 10000) 76 k, err := fi.Key() 77 if err != nil { 78 t.Fatal(err) 79 } 80 81 fname := path.Join(mnt.Dir, k.String()) 82 rbuf, err := ioutil.ReadFile(fname) 83 if err != nil { 84 t.Fatal(err) 85 } 86 87 if !bytes.Equal(rbuf, data) { 88 t.Fatal("Incorrect Read!") 89 } 90 } 91 92 func getPaths(t *testing.T, ipfs *core.IpfsNode, name string, n *dag.Node) []string { 93 if len(n.Links) == 0 { 94 return []string{name} 95 } 96 var out []string 97 for _, lnk := range n.Links { 98 child, err := lnk.GetNode(ipfs.Context(), ipfs.DAG) 99 if err != nil { 100 t.Fatal(err) 101 } 102 sub := getPaths(t, ipfs, path.Join(name, lnk.Name), child) 103 out = append(out, sub...) 104 } 105 return out 106 } 107 108 // Perform a large number of concurrent reads to stress the system 109 func TestIpfsStressRead(t *testing.T) { 110 if testing.Short() { 111 t.SkipNow() 112 } 113 nd, mnt := setupIpfsTest(t, nil) 114 defer mnt.Close() 115 116 var ks []key.Key 117 var paths []string 118 119 nobj := 50 120 ndiriter := 50 121 122 // Make a bunch of objects 123 for i := 0; i < nobj; i++ { 124 fi, _ := randObj(t, nd, rand.Int63n(50000)) 125 k, err := fi.Key() 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 ks = append(ks, k) 131 paths = append(paths, k.String()) 132 } 133 134 // Now make a bunch of dirs 135 for i := 0; i < ndiriter; i++ { 136 db := uio.NewDirectory(nd.DAG) 137 for j := 0; j < 1+rand.Intn(10); j++ { 138 name := fmt.Sprintf("child%d", j) 139 err := db.AddChild(name, ks[rand.Intn(len(ks))]) 140 if err != nil { 141 t.Fatal(err) 142 } 143 } 144 newdir := db.GetNode() 145 k, err := nd.DAG.Add(newdir) 146 if err != nil { 147 t.Fatal(err) 148 } 149 150 ks = append(ks, k) 151 npaths := getPaths(t, nd, k.String(), newdir) 152 paths = append(paths, npaths...) 153 } 154 155 // Now read a bunch, concurrently 156 wg := sync.WaitGroup{} 157 158 for s := 0; s < 4; s++ { 159 wg.Add(1) 160 go func() { 161 defer wg.Done() 162 163 for i := 0; i < 2000; i++ { 164 item := paths[rand.Intn(len(paths))] 165 fname := path.Join(mnt.Dir, item) 166 rbuf, err := ioutil.ReadFile(fname) 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 read, err := coreunix.Cat(nd, item) 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 data, err := ioutil.ReadAll(read) 177 if err != nil { 178 t.Fatal(err) 179 } 180 181 if !bytes.Equal(rbuf, data) { 182 t.Fatal("Incorrect Read!") 183 } 184 } 185 }() 186 } 187 wg.Wait() 188 } 189 190 // Test writing a file and reading it back 191 func TestIpfsBasicDirRead(t *testing.T) { 192 if testing.Short() { 193 t.SkipNow() 194 } 195 nd, mnt := setupIpfsTest(t, nil) 196 defer mnt.Close() 197 198 // Make a 'file' 199 fi, data := randObj(t, nd, 10000) 200 k, err := fi.Key() 201 if err != nil { 202 t.Fatal(err) 203 } 204 205 // Make a directory and put that file in it 206 db := uio.NewDirectory(nd.DAG) 207 err = db.AddChild("actual", k) 208 if err != nil { 209 t.Fatal(err) 210 } 211 212 d1nd := db.GetNode() 213 d1ndk, err := nd.DAG.Add(d1nd) 214 if err != nil { 215 t.Fatal(err) 216 } 217 218 dirname := path.Join(mnt.Dir, d1ndk.String()) 219 fname := path.Join(dirname, "actual") 220 rbuf, err := ioutil.ReadFile(fname) 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 dirents, err := ioutil.ReadDir(dirname) 226 if err != nil { 227 t.Fatal(err) 228 } 229 if len(dirents) != 1 { 230 t.Fatal("Bad directory entry count") 231 } 232 if dirents[0].Name() != "actual" { 233 t.Fatal("Bad directory entry") 234 } 235 236 if !bytes.Equal(rbuf, data) { 237 t.Fatal("Incorrect Read!") 238 } 239 } 240 241 // Test to make sure the filesystem reports file sizes correctly 242 func TestFileSizeReporting(t *testing.T) { 243 if testing.Short() { 244 t.SkipNow() 245 } 246 nd, mnt := setupIpfsTest(t, nil) 247 defer mnt.Close() 248 249 fi, data := randObj(t, nd, 10000) 250 k, err := fi.Key() 251 if err != nil { 252 t.Fatal(err) 253 } 254 255 fname := path.Join(mnt.Dir, k.String()) 256 257 finfo, err := os.Stat(fname) 258 if err != nil { 259 t.Fatal(err) 260 } 261 262 if finfo.Size() != int64(len(data)) { 263 t.Fatal("Read incorrect size from stat!") 264 } 265 }