merkledag_test.go 7 KB
Newer Older
1
package merkledag_test
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
2 3

import (
4
	"bytes"
5
	"errors"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6
	"fmt"
7 8
	"io"
	"io/ioutil"
9
	"strings"
10
	"sync"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11
	"testing"
12

13
	key "github.com/ipfs/go-ipfs/blocks/key"
14
	bserv "github.com/ipfs/go-ipfs/blockservice"
15
	bstest "github.com/ipfs/go-ipfs/blockservice/test"
16 17 18 19
	offline "github.com/ipfs/go-ipfs/exchange/offline"
	imp "github.com/ipfs/go-ipfs/importer"
	chunk "github.com/ipfs/go-ipfs/importer/chunk"
	. "github.com/ipfs/go-ipfs/merkledag"
20
	dstest "github.com/ipfs/go-ipfs/merkledag/test"
21
	uio "github.com/ipfs/go-ipfs/unixfs/io"
22
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
Jeromy's avatar
Jeromy committed
23
	"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26 27
)

func TestNode(t *testing.T) {

28 29 30
	n1 := NodeWithData([]byte("beep"))
	n2 := NodeWithData([]byte("boop"))
	n3 := NodeWithData([]byte("beep boop"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
31 32 33 34 35 36 37 38 39
	if err := n3.AddNodeLink("beep-link", n1); err != nil {
		t.Error(err)
	}
	if err := n3.AddNodeLink("boop-link", n2); err != nil {
		t.Error(err)
	}

	printn := func(name string, n *Node) {
		fmt.Println(">", name)
40
		fmt.Println("data:", string(n.Data()))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41 42 43 44 45 46

		fmt.Println("links:")
		for _, l := range n.Links {
			fmt.Println("-", l.Name, l.Size, l.Hash)
		}

47
		e, err := n.EncodeProtobuf(false)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
48 49 50 51 52 53 54 55 56 57 58 59
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("encoded:", e)
		}

		h, err := n.Multihash()
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("hash:", h)
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
60 61 62 63

		k, err := n.Key()
		if err != nil {
			t.Error(err)
64
		} else if k != key.Key(h) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65 66 67 68
			t.Error("Key is not equivalent to multihash")
		} else {
			fmt.Println("key: ", k)
		}
69 70

		SubtestNodeStat(t, n)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71 72 73 74 75 76
	}

	printn("beep", n1)
	printn("boop", n2)
	printn("beep boop", n3)
}
77

78
func SubtestNodeStat(t *testing.T, n *Node) {
79
	enc, err := n.EncodeProtobuf(true)
80
	if err != nil {
81
		t.Error("n.EncodeProtobuf(true) failed")
82 83 84 85 86 87 88 89 90
		return
	}

	cumSize, err := n.Size()
	if err != nil {
		t.Error("n.Size() failed")
		return
	}

91 92 93 94 95 96
	k, err := n.Key()
	if err != nil {
		t.Error("n.Key() failed")
		return
	}

97 98 99
	expected := NodeStat{
		NumLinks:       len(n.Links),
		BlockSize:      len(enc),
100 101
		LinksSize:      len(enc) - len(n.Data()), // includes framing.
		DataSize:       len(n.Data()),
102
		CumulativeSize: int(cumSize),
103
		Hash:           k.B58String(),
104 105 106 107 108 109 110 111
	}

	actual, err := n.Stat()
	if err != nil {
		t.Error("n.Stat() failed")
		return
	}

112
	if expected != *actual {
113
		t.Errorf("n.Stat incorrect.\nexpect: %s\nactual: %s", expected, actual)
114 115 116 117 118
	} else {
		fmt.Printf("n.Stat correct: %s\n", actual)
	}
}

119 120 121
type devZero struct{}

func (_ devZero) Read(b []byte) (int, error) {
rht's avatar
rht committed
122
	for i := range b {
123 124 125 126 127
		b[i] = 0
	}
	return len(b), nil
}

128
func TestBatchFetch(t *testing.T) {
Jeromy's avatar
Jeromy committed
129 130
	read := io.LimitReader(u.NewTimeSeededRand(), 1024*32)
	runBatchFetchTest(t, read)
131
}
132 133

func TestBatchFetchDupBlock(t *testing.T) {
Jeromy's avatar
Jeromy committed
134 135
	read := io.LimitReader(devZero{}, 1024*32)
	runBatchFetchTest(t, read)
136 137
}

Jeromy's avatar
Jeromy committed
138
func runBatchFetchTest(t *testing.T, read io.Reader) {
139
	ctx := context.Background()
140
	var dagservs []DAGService
141
	for _, bsi := range bstest.Mocks(5) {
142 143
		dagservs = append(dagservs, NewDAGService(bsi))
	}
Jeromy's avatar
Jeromy committed
144

145
	spl := chunk.NewSizeSplitter(read, 512)
Jeromy's avatar
Jeromy committed
146

Jeromy's avatar
Jeromy committed
147
	root, err := imp.BuildDagFromReader(dagservs[0], spl)
Jeromy's avatar
Jeromy committed
148 149 150 151
	if err != nil {
		t.Fatal(err)
	}

152 153
	t.Log("finished setup.")

154
	dagr, err := uio.NewDagReader(ctx, root, dagservs[0])
155 156 157
	if err != nil {
		t.Fatal(err)
	}
Jeromy's avatar
Jeromy committed
158 159

	expected, err := ioutil.ReadAll(dagr)
160 161 162 163
	if err != nil {
		t.Fatal(err)
	}

164
	_, err = dagservs[0].Add(root)
165 166 167 168 169 170 171 172 173 174 175
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Added file to first node.")

	k, err := root.Key()
	if err != nil {
		t.Fatal(err)
	}

176
	wg := sync.WaitGroup{}
177 178
	errs := make(chan error)

179
	for i := 1; i < len(dagservs); i++ {
180
		wg.Add(1)
181
		go func(i int) {
182
			defer wg.Done()
183
			first, err := dagservs[i].Get(ctx, k)
184
			if err != nil {
185
				errs <- err
186 187 188
			}
			fmt.Println("Got first node back.")

189
			read, err := uio.NewDagReader(ctx, first, dagservs[i])
190
			if err != nil {
191
				errs <- err
192 193 194
			}
			datagot, err := ioutil.ReadAll(read)
			if err != nil {
195
				errs <- err
196 197 198
			}

			if !bytes.Equal(datagot, expected) {
199
				errs <- errors.New("Got bad data back!")
200 201 202 203
			}
		}(i)
	}

204 205 206 207 208 209 210 211 212 213
	go func() {
		wg.Wait()
		close(errs)
	}()

	for err := range errs {
		if err != nil {
			t.Fatal(err)
		}
	}
214
}
215 216 217 218 219 220 221

func assertCanGet(t *testing.T, ds DAGService, n *Node) {
	k, err := n.Key()
	if err != nil {
		t.Fatal(err)
	}

222
	if _, err := ds.Get(context.Background(), k); err != nil {
223 224 225 226
		t.Fatal(err)
	}
}

jbenet's avatar
jbenet committed
227
func TestEmptyKey(t *testing.T) {
Juan Benet's avatar
Juan Benet committed
228
	ds := dstest.Mock()
jbenet's avatar
jbenet committed
229 230 231 232 233 234
	_, err := ds.Get(context.Background(), key.Key(""))
	if err != ErrNotFound {
		t.Error("dag service should error when key is nil", err)
	}
}

235
func TestCantGet(t *testing.T) {
236
	ds := dstest.Mock()
237
	a := NodeWithData([]byte("A"))
238 239 240 241 242 243

	k, err := a.Key()
	if err != nil {
		t.Fatal(err)
	}

244
	_, err = ds.Get(context.Background(), k)
245 246 247 248
	if !strings.Contains(err.Error(), "not found") {
		t.Fatal("expected err not found, got: ", err)
	}
}
249 250

func TestFetchGraph(t *testing.T) {
Jeromy's avatar
Jeromy committed
251
	var dservs []DAGService
252
	bsis := bstest.Mocks(2)
Jeromy's avatar
Jeromy committed
253 254 255
	for _, bsi := range bsis {
		dservs = append(dservs, NewDAGService(bsi))
	}
256 257

	read := io.LimitReader(u.NewTimeSeededRand(), 1024*32)
Jeromy's avatar
Jeromy committed
258
	root, err := imp.BuildDagFromReader(dservs[0], chunk.NewSizeSplitter(read, 512))
259 260 261 262
	if err != nil {
		t.Fatal(err)
	}

Jeromy's avatar
Jeromy committed
263
	err = FetchGraph(context.TODO(), root, dservs[1])
264 265 266 267
	if err != nil {
		t.Fatal(err)
	}

Jeromy's avatar
Jeromy committed
268
	// create an offline dagstore and ensure all blocks were fetched
269
	bs := bserv.New(bsis[1].Blockstore, offline.Exchange(bsis[1].Blockstore))
270

Jeromy's avatar
Jeromy committed
271 272 273
	offline_ds := NewDAGService(bs)
	ks := key.NewKeySet()

274
	err = EnumerateChildren(context.Background(), offline_ds, root, ks, false)
275 276 277 278 279 280
	if err != nil {
		t.Fatal(err)
	}
}

func TestEnumerateChildren(t *testing.T) {
281
	bsi := bstest.Mocks(1)
282 283 284
	ds := NewDAGService(bsi[0])

	read := io.LimitReader(u.NewTimeSeededRand(), 1024*1024)
Jeromy's avatar
Jeromy committed
285
	root, err := imp.BuildDagFromReader(ds, chunk.NewSizeSplitter(read, 512))
286 287 288 289 290
	if err != nil {
		t.Fatal(err)
	}

	ks := key.NewKeySet()
291
	err = EnumerateChildren(context.Background(), ds, root, ks, false)
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
	if err != nil {
		t.Fatal(err)
	}

	var traverse func(n *Node)
	traverse = func(n *Node) {
		// traverse dag and check
		for _, lnk := range n.Links {
			k := key.Key(lnk.Hash)
			if !ks.Has(k) {
				t.Fatal("missing key in set!")
			}
			child, err := ds.Get(context.Background(), k)
			if err != nil {
				t.Fatal(err)
			}
			traverse(child)
		}
	}

	traverse(root)
}
314 315 316 317 318 319 320

func TestFetchFailure(t *testing.T) {
	ds := dstest.Mock()
	ds_bad := dstest.Mock()

	top := new(Node)
	for i := 0; i < 10; i++ {
321
		nd := NodeWithData([]byte{byte('a' + i)})
322 323 324 325 326 327 328 329 330 331 332 333
		_, err := ds.Add(nd)
		if err != nil {
			t.Fatal(err)
		}

		err = top.AddNodeLinkClean(fmt.Sprintf("AA%d", i), nd)
		if err != nil {
			t.Fatal(err)
		}
	}

	for i := 0; i < 10; i++ {
334
		nd := NodeWithData([]byte{'f', 'a' + byte(i)})
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
		_, err := ds_bad.Add(nd)
		if err != nil {
			t.Fatal(err)
		}

		err = top.AddNodeLinkClean(fmt.Sprintf("BB%d", i), nd)
		if err != nil {
			t.Fatal(err)
		}
	}

	getters := GetDAG(context.Background(), ds, top)
	for i, getter := range getters {
		_, err := getter.Get(context.Background())
		if err != nil && i < 10 {
			t.Fatal(err)
		}
		if err == nil && i >= 10 {
			t.Fatal("should have failed request")
		}
	}
}