@cryptotaxi247 / kubo / commits / e60f2ba56

coreapi: move tests to interface subpackage

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com> This commit was moved from ipfs/interface-go-ipfs-core@a479105a40eddefc84ca1de9aaaf12cbe2e13e56 This commit was moved from ipfs/boxo@3301b037c33fd42e0deb10965447a7e26e1e86fa

Łukasz Magiera committed Dec 20, 2018 at 19:45 UTC e60f2ba563c6a5708ba08c8140ac517b206dfda6
10 files changed +3061
core/coreiface/tests/block_test.go new
+183
@@ -0,0 +1,183 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "io/ioutil"
6 + "strings"
7 + "testing"
8 +
9 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
10 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
11 +
12 + mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
13 +)
14 +
15 +func TestBlockPut(t *testing.T) {
16 + ctx := context.Background()
17 + api, err := makeAPI(ctx)
18 + if err != nil {
19 + t.Error(err)
20 + }
21 +
22 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`))
23 + if err != nil {
24 + t.Error(err)
25 + }
26 +
27 + if res.Path().Cid().String() != "QmPyo15ynbVrSTVdJL9th7JysHaAbXt9dM9tXk1bMHbRtk" {
28 + t.Errorf("got wrong cid: %s", res.Path().Cid().String())
29 + }
30 +}
31 +
32 +func TestBlockPutFormat(t *testing.T) {
33 + ctx := context.Background()
34 + api, err := makeAPI(ctx)
35 + if err != nil {
36 + t.Error(err)
37 + }
38 +
39 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), opt.Block.Format("cbor"))
40 + if err != nil {
41 + t.Error(err)
42 + }
43 +
44 + if res.Path().Cid().String() != "zdpuAn4amuLWo8Widi5v6VQpuo2dnpnwbVE3oB6qqs7mDSeoa" {
45 + t.Errorf("got wrong cid: %s", res.Path().Cid().String())
46 + }
47 +}
48 +
49 +func TestBlockPutHash(t *testing.T) {
50 + ctx := context.Background()
51 + api, err := makeAPI(ctx)
52 + if err != nil {
53 + t.Error(err)
54 + }
55 +
56 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), opt.Block.Hash(mh.KECCAK_512, -1))
57 + if err != nil {
58 + t.Fatal(err)
59 + }
60 +
61 + if res.Path().Cid().String() != "zBurKB9YZkcDf6xa53WBE8CFX4ydVqAyf9KPXBFZt5stJzEstaS8Hukkhu4gwpMtc1xHNDbzP7sPtQKyWsP3C8fbhkmrZ" {
62 + t.Errorf("got wrong cid: %s", res.Path().Cid().String())
63 + }
64 +}
65 +
66 +func TestBlockGet(t *testing.T) {
67 + ctx := context.Background()
68 + api, err := makeAPI(ctx)
69 + if err != nil {
70 + t.Error(err)
71 + }
72 +
73 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), opt.Block.Hash(mh.KECCAK_512, -1))
74 + if err != nil {
75 + t.Error(err)
76 + }
77 +
78 + r, err := api.Block().Get(ctx, res.Path())
79 + if err != nil {
80 + t.Error(err)
81 + }
82 +
83 + d, err := ioutil.ReadAll(r)
84 + if err != nil {
85 + t.Error(err)
86 + }
87 +
88 + if string(d) != "Hello" {
89 + t.Error("didn't get correct data back")
90 + }
91 +
92 + p, err := coreiface.ParsePath("/ipfs/" + res.Path().Cid().String())
93 + if err != nil {
94 + t.Error(err)
95 + }
96 +
97 + rp, err := api.ResolvePath(ctx, p)
98 + if err != nil {
99 + t.Fatal(err)
100 + }
101 + if rp.Cid().String() != res.Path().Cid().String() {
102 + t.Error("paths didn't match")
103 + }
104 +}
105 +
106 +func TestBlockRm(t *testing.T) {
107 + ctx := context.Background()
108 + api, err := makeAPI(ctx)
109 + if err != nil {
110 + t.Error(err)
111 + }
112 +
113 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`))
114 + if err != nil {
115 + t.Error(err)
116 + }
117 +
118 + r, err := api.Block().Get(ctx, res.Path())
119 + if err != nil {
120 + t.Error(err)
121 + }
122 +
123 + d, err := ioutil.ReadAll(r)
124 + if err != nil {
125 + t.Error(err)
126 + }
127 +
128 + if string(d) != "Hello" {
129 + t.Error("didn't get correct data back")
130 + }
131 +
132 + err = api.Block().Rm(ctx, res.Path())
133 + if err != nil {
134 + t.Error(err)
135 + }
136 +
137 + _, err = api.Block().Get(ctx, res.Path())
138 + if err == nil {
139 + t.Error("expected err to exist")
140 + }
141 + if err.Error() != "blockservice: key not found" {
142 + t.Errorf("unexpected error; %s", err.Error())
143 + }
144 +
145 + err = api.Block().Rm(ctx, res.Path())
146 + if err == nil {
147 + t.Error("expected err to exist")
148 + }
149 + if err.Error() != "blockstore: block not found" {
150 + t.Errorf("unexpected error; %s", err.Error())
151 + }
152 +
153 + err = api.Block().Rm(ctx, res.Path(), opt.Block.Force(true))
154 + if err != nil {
155 + t.Error(err)
156 + }
157 +}
158 +
159 +func TestBlockStat(t *testing.T) {
160 + ctx := context.Background()
161 + api, err := makeAPI(ctx)
162 + if err != nil {
163 + t.Error(err)
164 + }
165 +
166 + res, err := api.Block().Put(ctx, strings.NewReader(`Hello`))
167 + if err != nil {
168 + t.Error(err)
169 + }
170 +
171 + stat, err := api.Block().Stat(ctx, res.Path())
172 + if err != nil {
173 + t.Error(err)
174 + }
175 +
176 + if stat.Path().String() != res.Path().String() {
177 + t.Error("paths don't match")
178 + }
179 +
180 + if stat.Size() != len("Hello") {
181 + t.Error("length doesn't match")
182 + }
183 +}
core/coreiface/tests/dag_test.go new
+151
@@ -0,0 +1,151 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "path"
6 + "strings"
7 + "testing"
8 +
9 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
10 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
11 +
12 + mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
13 +)
14 +
15 +var (
16 + treeExpected = map[string]struct{}{
17 + "a": {},
18 + "b": {},
19 + "c": {},
20 + "c/d": {},
21 + "c/e": {},
22 + }
23 +)
24 +
25 +func TestPut(t *testing.T) {
26 + ctx := context.Background()
27 + api, err := makeAPI(ctx)
28 + if err != nil {
29 + t.Error(err)
30 + }
31 +
32 + res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`))
33 + if err != nil {
34 + t.Error(err)
35 + }
36 +
37 + if res.Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
38 + t.Errorf("got wrong cid: %s", res.Cid().String())
39 + }
40 +}
41 +
42 +func TestPutWithHash(t *testing.T) {
43 + ctx := context.Background()
44 + api, err := makeAPI(ctx)
45 + if err != nil {
46 + t.Error(err)
47 + }
48 +
49 + res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`), opt.Dag.Hash(mh.ID, -1))
50 + if err != nil {
51 + t.Error(err)
52 + }
53 +
54 + if res.Cid().String() != "z5hRLNd2sv4z1c" {
55 + t.Errorf("got wrong cid: %s", res.Cid().String())
56 + }
57 +}
58 +
59 +func TestPath(t *testing.T) {
60 + ctx := context.Background()
61 + api, err := makeAPI(ctx)
62 + if err != nil {
63 + t.Error(err)
64 + }
65 +
66 + sub, err := api.Dag().Put(ctx, strings.NewReader(`"foo"`))
67 + if err != nil {
68 + t.Error(err)
69 + }
70 +
71 + res, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+sub.Cid().String()+`"}}`))
72 + if err != nil {
73 + t.Error(err)
74 + }
75 +
76 + p, err := coreiface.ParsePath(path.Join(res.Cid().String(), "lnk"))
77 + if err != nil {
78 + t.Error(err)
79 + }
80 +
81 + nd, err := api.Dag().Get(ctx, p)
82 + if err != nil {
83 + t.Error(err)
84 + }
85 +
86 + if nd.Cid().String() != sub.Cid().String() {
87 + t.Errorf("got unexpected cid %s, expected %s", nd.Cid().String(), sub.Cid().String())
88 + }
89 +}
90 +
91 +func TestTree(t *testing.T) {
92 + ctx := context.Background()
93 + api, err := makeAPI(ctx)
94 + if err != nil {
95 + t.Error(err)
96 + }
97 +
98 + c, err := api.Dag().Put(ctx, strings.NewReader(`{"a": 123, "b": "foo", "c": {"d": 321, "e": 111}}`))
99 + if err != nil {
100 + t.Error(err)
101 + }
102 +
103 + res, err := api.Dag().Get(ctx, c)
104 + if err != nil {
105 + t.Error(err)
106 + }
107 +
108 + lst := res.Tree("", -1)
109 + if len(lst) != len(treeExpected) {
110 + t.Errorf("tree length of %d doesn't match expected %d", len(lst), len(treeExpected))
111 + }
112 +
113 + for _, ent := range lst {
114 + if _, ok := treeExpected[ent]; !ok {
115 + t.Errorf("unexpected tree entry %s", ent)
116 + }
117 + }
118 +}
119 +
120 +func TestBatch(t *testing.T) {
121 + ctx := context.Background()
122 + api, err := makeAPI(ctx)
123 + if err != nil {
124 + t.Error(err)
125 + }
126 +
127 + batch := api.Dag().Batch(ctx)
128 +
129 + c, err := batch.Put(ctx, strings.NewReader(`"Hello"`))
130 + if err != nil {
131 + t.Error(err)
132 + }
133 +
134 + if c.Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
135 + t.Errorf("got wrong cid: %s", c.Cid().String())
136 + }
137 +
138 + _, err = api.Dag().Get(ctx, c)
139 + if err == nil || err.Error() != "merkledag: not found" {
140 + t.Error(err)
141 + }
142 +
143 + if err := batch.Commit(ctx); err != nil {
144 + t.Error(err)
145 + }
146 +
147 + _, err = api.Dag().Get(ctx, c)
148 + if err != nil {
149 + t.Error(err)
150 + }
151 +}
core/coreiface/tests/dht_test.go new
+126
@@ -0,0 +1,126 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "io"
6 + "testing"
7 +
8 + "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
9 +)
10 +
11 +func TestDhtFindPeer(t *testing.T) {
12 + ctx := context.Background()
13 + apis, err := makeAPISwarm(ctx, true, 5)
14 + if err != nil {
15 + t.Fatal(err)
16 + }
17 +
18 + self0, err := apis[0].Key().Self(ctx)
19 + if err != nil {
20 + t.Fatal(err)
21 + }
22 +
23 + pi, err := apis[2].Dht().FindPeer(ctx, self0.ID())
24 + if err != nil {
25 + t.Fatal(err)
26 + }
27 +
28 + if pi.Addrs[0].String() != "/ip4/127.0.0.1/tcp/4001" {
29 + t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
30 + }
31 +
32 + self2, err := apis[2].Key().Self(ctx)
33 + if err != nil {
34 + t.Fatal(err)
35 + }
36 +
37 + pi, err = apis[1].Dht().FindPeer(ctx, self2.ID())
38 + if err != nil {
39 + t.Fatal(err)
40 + }
41 +
42 + if pi.Addrs[0].String() != "/ip4/127.0.2.1/tcp/4001" {
43 + t.Errorf("got unexpected address from FindPeer: %s", pi.Addrs[0].String())
44 + }
45 +}
46 +
47 +func TestDhtFindProviders(t *testing.T) {
48 + ctx := context.Background()
49 + apis, err := makeAPISwarm(ctx, true, 5)
50 + if err != nil {
51 + t.Fatal(err)
52 + }
53 +
54 + p, err := addTestObject(ctx, apis[0])
55 + if err != nil {
56 + t.Fatal(err)
57 + }
58 +
59 + out, err := apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
60 + if err != nil {
61 + t.Fatal(err)
62 + }
63 +
64 + provider := <-out
65 +
66 + self0, err := apis[0].Key().Self(ctx)
67 + if err != nil {
68 + t.Fatal(err)
69 + }
70 +
71 + if provider.ID.String() != self0.ID().String() {
72 + t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
73 + }
74 +}
75 +
76 +func TestDhtProvide(t *testing.T) {
77 + ctx := context.Background()
78 + apis, err := makeAPISwarm(ctx, true, 5)
79 + if err != nil {
80 + t.Fatal(err)
81 + }
82 +
83 + off0, err := apis[0].WithOptions(options.Api.Offline(true))
84 + if err != nil {
85 + t.Fatal(err)
86 + }
87 +
88 + s, err := off0.Block().Put(ctx, &io.LimitedReader{R: rnd, N: 4092})
89 + if err != nil {
90 + t.Fatal(err)
91 + }
92 +
93 + p := s.Path()
94 +
95 + out, err := apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
96 + if err != nil {
97 + t.Fatal(err)
98 + }
99 +
100 + provider := <-out
101 +
102 + self0, err := apis[0].Key().Self(ctx)
103 + if err != nil {
104 + t.Fatal(err)
105 + }
106 +
107 + if provider.ID.String() != "<peer.ID >" {
108 + t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
109 + }
110 +
111 + err = apis[0].Dht().Provide(ctx, p)
112 + if err != nil {
113 + t.Fatal(err)
114 + }
115 +
116 + out, err = apis[2].Dht().FindProviders(ctx, p, options.Dht.NumProviders(1))
117 + if err != nil {
118 + t.Fatal(err)
119 + }
120 +
121 + provider = <-out
122 +
123 + if provider.ID.String() != self0.ID().String() {
124 + t.Errorf("got wrong provider: %s != %s", provider.ID.String(), self0.ID().String())
125 + }
126 +}
core/coreiface/tests/key_test.go new
+475
@@ -0,0 +1,475 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "strings"
6 + "testing"
7 +
8 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
9 +)
10 +
11 +func TestListSelf(t *testing.T) {
12 + ctx := context.Background()
13 + api, err := makeAPI(ctx)
14 + if err != nil {
15 + t.Fatal(err)
16 + return
17 + }
18 +
19 + keys, err := api.Key().List(ctx)
20 + if err != nil {
21 + t.Fatalf("failed to list keys: %s", err)
22 + return
23 + }
24 +
25 + if len(keys) != 1 {
26 + t.Fatalf("there should be 1 key (self), got %d", len(keys))
27 + return
28 + }
29 +
30 + if keys[0].Name() != "self" {
31 + t.Errorf("expected the key to be called 'self', got '%s'", keys[0].Name())
32 + }
33 +
34 + if keys[0].Path().String() != "/ipns/"+testPeerID {
35 + t.Errorf("expected the key to have path '/ipns/%s', got '%s'", testPeerID, keys[0].Path().String())
36 + }
37 +}
38 +
39 +func TestRenameSelf(t *testing.T) {
40 + ctx := context.Background()
41 + api, err := makeAPI(ctx)
42 + if err != nil {
43 + t.Fatal(err)
44 + return
45 + }
46 +
47 + _, _, err = api.Key().Rename(ctx, "self", "foo")
48 + if err == nil {
49 + t.Error("expected error to not be nil")
50 + } else {
51 + if err.Error() != "cannot rename key with name 'self'" {
52 + t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
53 + }
54 + }
55 +
56 + _, _, err = api.Key().Rename(ctx, "self", "foo", opt.Key.Force(true))
57 + if err == nil {
58 + t.Error("expected error to not be nil")
59 + } else {
60 + if err.Error() != "cannot rename key with name 'self'" {
61 + t.Fatalf("expected error 'cannot rename key with name 'self'', got '%s'", err.Error())
62 + }
63 + }
64 +}
65 +
66 +func TestRemoveSelf(t *testing.T) {
67 + ctx := context.Background()
68 + api, err := makeAPI(ctx)
69 + if err != nil {
70 + t.Fatal(err)
71 + return
72 + }
73 +
74 + _, err = api.Key().Remove(ctx, "self")
75 + if err == nil {
76 + t.Error("expected error to not be nil")
77 + } else {
78 + if err.Error() != "cannot remove key with name 'self'" {
79 + t.Fatalf("expected error 'cannot remove key with name 'self'', got '%s'", err.Error())
80 + }
81 + }
82 +}
83 +
84 +func TestGenerate(t *testing.T) {
85 + ctx := context.Background()
86 + api, err := makeAPI(ctx)
87 + if err != nil {
88 + t.Error(err)
89 + }
90 +
91 + k, err := api.Key().Generate(ctx, "foo")
92 + if err != nil {
93 + t.Fatal(err)
94 + return
95 + }
96 +
97 + if k.Name() != "foo" {
98 + t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
99 + }
100 +
101 + if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
102 + t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
103 + }
104 +}
105 +
106 +func TestGenerateSize(t *testing.T) {
107 + ctx := context.Background()
108 + api, err := makeAPI(ctx)
109 + if err != nil {
110 + t.Error(err)
111 + }
112 +
113 + k, err := api.Key().Generate(ctx, "foo", opt.Key.Size(1024))
114 + if err != nil {
115 + t.Fatal(err)
116 + return
117 + }
118 +
119 + if k.Name() != "foo" {
120 + t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
121 + }
122 +
123 + if !strings.HasPrefix(k.Path().String(), "/ipns/Qm") {
124 + t.Errorf("expected the key to be prefixed with '/ipns/Qm', got '%s'", k.Path().String())
125 + }
126 +}
127 +
128 +func TestGenerateType(t *testing.T) {
129 + ctx := context.Background()
130 + t.Skip("disabled until libp2p/specs#111 is fixed")
131 +
132 + api, err := makeAPI(ctx)
133 + if err != nil {
134 + t.Error(err)
135 + }
136 +
137 + k, err := api.Key().Generate(ctx, "bar", opt.Key.Type(opt.Ed25519Key))
138 + if err != nil {
139 + t.Fatal(err)
140 + return
141 + }
142 +
143 + if k.Name() != "bar" {
144 + t.Errorf("expected the key to be called 'foo', got '%s'", k.Name())
145 + }
146 +
147 + // Expected to be an inlined identity hash.
148 + if !strings.HasPrefix(k.Path().String(), "/ipns/12") {
149 + t.Errorf("expected the key to be prefixed with '/ipns/12', got '%s'", k.Path().String())
150 + }
151 +}
152 +
153 +func TestGenerateExisting(t *testing.T) {
154 + ctx := context.Background()
155 + api, err := makeAPI(ctx)
156 + if err != nil {
157 + t.Error(err)
158 + }
159 +
160 + _, err = api.Key().Generate(ctx, "foo")
161 + if err != nil {
162 + t.Fatal(err)
163 + return
164 + }
165 +
166 + _, err = api.Key().Generate(ctx, "foo")
167 + if err == nil {
168 + t.Error("expected error to not be nil")
169 + } else {
170 + if err.Error() != "key with name 'foo' already exists" {
171 + t.Fatalf("expected error 'key with name 'foo' already exists', got '%s'", err.Error())
172 + }
173 + }
174 +
175 + _, err = api.Key().Generate(ctx, "self")
176 + if err == nil {
177 + t.Error("expected error to not be nil")
178 + } else {
179 + if err.Error() != "cannot create key with name 'self'" {
180 + t.Fatalf("expected error 'cannot create key with name 'self'', got '%s'", err.Error())
181 + }
182 + }
183 +}
184 +
185 +func TestList(t *testing.T) {
186 + ctx := context.Background()
187 + api, err := makeAPI(ctx)
188 + if err != nil {
189 + t.Error(err)
190 + }
191 +
192 + _, err = api.Key().Generate(ctx, "foo")
193 + if err != nil {
194 + t.Fatal(err)
195 + return
196 + }
197 +
198 + l, err := api.Key().List(ctx)
199 + if err != nil {
200 + t.Fatal(err)
201 + return
202 + }
203 +
204 + if len(l) != 2 {
205 + t.Fatalf("expected to get 2 keys, got %d", len(l))
206 + return
207 + }
208 +
209 + if l[0].Name() != "self" {
210 + t.Fatalf("expected key 0 to be called 'self', got '%s'", l[0].Name())
211 + return
212 + }
213 +
214 + if l[1].Name() != "foo" {
215 + t.Fatalf("expected key 1 to be called 'foo', got '%s'", l[1].Name())
216 + return
217 + }
218 +
219 + if !strings.HasPrefix(l[0].Path().String(), "/ipns/Qm") {
220 + t.Fatalf("expected key 0 to be prefixed with '/ipns/Qm', got '%s'", l[0].Name())
221 + return
222 + }
223 +
224 + if !strings.HasPrefix(l[1].Path().String(), "/ipns/Qm") {
225 + t.Fatalf("expected key 1 to be prefixed with '/ipns/Qm', got '%s'", l[1].Name())
226 + return
227 + }
228 +}
229 +
230 +func TestRename(t *testing.T) {
231 + ctx := context.Background()
232 + api, err := makeAPI(ctx)
233 + if err != nil {
234 + t.Error(err)
235 + }
236 +
237 + _, err = api.Key().Generate(ctx, "foo")
238 + if err != nil {
239 + t.Fatal(err)
240 + return
241 + }
242 +
243 + k, overwrote, err := api.Key().Rename(ctx, "foo", "bar")
244 + if err != nil {
245 + t.Fatal(err)
246 + return
247 + }
248 +
249 + if overwrote {
250 + t.Error("overwrote should be false")
251 + }
252 +
253 + if k.Name() != "bar" {
254 + t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
255 + }
256 +}
257 +
258 +func TestRenameToSelf(t *testing.T) {
259 + ctx := context.Background()
260 + api, err := makeAPI(ctx)
261 + if err != nil {
262 + t.Error(err)
263 + }
264 +
265 + _, err = api.Key().Generate(ctx, "foo")
266 + if err != nil {
267 + t.Fatal(err)
268 + return
269 + }
270 +
271 + _, _, err = api.Key().Rename(ctx, "foo", "self")
272 + if err == nil {
273 + t.Error("expected error to not be nil")
274 + } else {
275 + if err.Error() != "cannot overwrite key with name 'self'" {
276 + t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
277 + }
278 + }
279 +}
280 +
281 +func TestRenameToSelfForce(t *testing.T) {
282 + ctx := context.Background()
283 + api, err := makeAPI(ctx)
284 + if err != nil {
285 + t.Error(err)
286 + }
287 +
288 + _, err = api.Key().Generate(ctx, "foo")
289 + if err != nil {
290 + t.Fatal(err)
291 + return
292 + }
293 +
294 + _, _, err = api.Key().Rename(ctx, "foo", "self", opt.Key.Force(true))
295 + if err == nil {
296 + t.Error("expected error to not be nil")
297 + } else {
298 + if err.Error() != "cannot overwrite key with name 'self'" {
299 + t.Fatalf("expected error 'cannot overwrite key with name 'self'', got '%s'", err.Error())
300 + }
301 + }
302 +}
303 +
304 +func TestRenameOverwriteNoForce(t *testing.T) {
305 + ctx := context.Background()
306 + api, err := makeAPI(ctx)
307 + if err != nil {
308 + t.Error(err)
309 + }
310 +
311 + _, err = api.Key().Generate(ctx, "foo")
312 + if err != nil {
313 + t.Fatal(err)
314 + return
315 + }
316 +
317 + _, err = api.Key().Generate(ctx, "bar")
318 + if err != nil {
319 + t.Fatal(err)
320 + return
321 + }
322 +
323 + _, _, err = api.Key().Rename(ctx, "foo", "bar")
324 + if err == nil {
325 + t.Error("expected error to not be nil")
326 + } else {
327 + if err.Error() != "key by that name already exists, refusing to overwrite" {
328 + t.Fatalf("expected error 'key by that name already exists, refusing to overwrite', got '%s'", err.Error())
329 + }
330 + }
331 +}
332 +
333 +func TestRenameOverwrite(t *testing.T) {
334 + ctx := context.Background()
335 + api, err := makeAPI(ctx)
336 + if err != nil {
337 + t.Error(err)
338 + }
339 +
340 + kfoo, err := api.Key().Generate(ctx, "foo")
341 + if err != nil {
342 + t.Fatal(err)
343 + return
344 + }
345 +
346 + _, err = api.Key().Generate(ctx, "bar")
347 + if err != nil {
348 + t.Fatal(err)
349 + return
350 + }
351 +
352 + k, overwrote, err := api.Key().Rename(ctx, "foo", "bar", opt.Key.Force(true))
353 + if err != nil {
354 + t.Fatal(err)
355 + return
356 + }
357 +
358 + if !overwrote {
359 + t.Error("overwrote should be true")
360 + }
361 +
362 + if k.Name() != "bar" {
363 + t.Errorf("returned key should be called 'bar', got '%s'", k.Name())
364 + }
365 +
366 + if k.Path().String() != kfoo.Path().String() {
367 + t.Errorf("k and kfoo should have equal paths, '%s'!='%s'", k.Path().String(), kfoo.Path().String())
368 + }
369 +}
370 +
371 +func TestRenameSameNameNoForce(t *testing.T) {
372 + ctx := context.Background()
373 + api, err := makeAPI(ctx)
374 + if err != nil {
375 + t.Error(err)
376 + }
377 +
378 + _, err = api.Key().Generate(ctx, "foo")
379 + if err != nil {
380 + t.Fatal(err)
381 + return
382 + }
383 +
384 + k, overwrote, err := api.Key().Rename(ctx, "foo", "foo")
385 + if err != nil {
386 + t.Fatal(err)
387 + return
388 + }
389 +
390 + if overwrote {
391 + t.Error("overwrote should be false")
392 + }
393 +
394 + if k.Name() != "foo" {
395 + t.Errorf("returned key should be called 'foo', got '%s'", k.Name())
396 + }
397 +}
398 +
399 +func TestRenameSameName(t *testing.T) {
400 + ctx := context.Background()
401 + api, err := makeAPI(ctx)
402 + if err != nil {
403 + t.Error(err)
404 + }
405 +
406 + _, err = api.Key().Generate(ctx, "foo")
407 + if err != nil {
408 + t.Fatal(err)
409 + return
410 + }
411 +
412 + k, overwrote, err := api.Key().Rename(ctx, "foo", "foo", opt.Key.Force(true))
413 + if err != nil {
414 + t.Fatal(err)
415 + return
416 + }
417 +
418 + if overwrote {
419 + t.Error("overwrote should be false")
420 + }
421 +
422 + if k.Name() != "foo" {
423 + t.Errorf("returned key should be called 'foo', got '%s'", k.Name())
424 + }
425 +}
426 +
427 +func TestRemove(t *testing.T) {
428 + ctx := context.Background()
429 + api, err := makeAPI(ctx)
430 + if err != nil {
431 + t.Error(err)
432 + }
433 +
434 + k, err := api.Key().Generate(ctx, "foo")
435 + if err != nil {
436 + t.Fatal(err)
437 + return
438 + }
439 +
440 + l, err := api.Key().List(ctx)
441 + if err != nil {
442 + t.Fatal(err)
443 + return
444 + }
445 +
446 + if len(l) != 2 {
447 + t.Fatalf("expected to get 2 keys, got %d", len(l))
448 + return
449 + }
450 +
451 + p, err := api.Key().Remove(ctx, "foo")
452 + if err != nil {
453 + t.Fatal(err)
454 + return
455 + }
456 +
457 + if k.Path().String() != p.Path().String() {
458 + t.Errorf("k and p should have equal paths, '%s'!='%s'", k.Path().String(), p.Path().String())
459 + }
460 +
461 + l, err = api.Key().List(ctx)
462 + if err != nil {
463 + t.Fatal(err)
464 + return
465 + }
466 +
467 + if len(l) != 1 {
468 + t.Fatalf("expected to get 1 key, got %d", len(l))
469 + return
470 + }
471 +
472 + if l[0].Name() != "self" {
473 + t.Errorf("expected the key to be called 'self', got '%s'", l[0].Name())
474 + }
475 +}
core/coreiface/tests/name_test.go new
+262
@@ -0,0 +1,262 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "io"
6 + "math/rand"
7 + "path"
8 + "testing"
9 + "time"
10 +
11 + "gx/ipfs/QmXWZCd8jfaHmt4UDSnjKmGcrQMw95bDGWqEeVLVJjoANX/go-ipfs-files"
12 + ipath "gx/ipfs/QmZErC2Ay6WuGi96CPg316PwitdwgLo6RxZRqVjJjRj2MR/go-path"
13 +
14 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
15 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
16 +)
17 +
18 +var rnd = rand.New(rand.NewSource(0x62796532303137))
19 +
20 +func addTestObject(ctx context.Context, api coreiface.CoreAPI) (coreiface.Path, error) {
21 + return api.Unixfs().Add(ctx, files.NewReaderFile(&io.LimitedReader{R: rnd, N: 4092}))
22 +}
23 +
24 +func appendPath(p coreiface.Path, sub string) coreiface.Path {
25 + p, err := coreiface.ParsePath(path.Join(p.String(), sub))
26 + if err != nil {
27 + panic(err)
28 + }
29 + return p
30 +}
31 +
32 +func TestPublishResolve(t *testing.T) {
33 + ctx := context.Background()
34 + init := func() (coreiface.CoreAPI, coreiface.Path) {
35 + apis, err := makeAPISwarm(ctx, true, 5)
36 + if err != nil {
37 + t.Fatal(err)
38 + return nil, nil
39 + }
40 + api := apis[0]
41 +
42 + p, err := addTestObject(ctx, api)
43 + if err != nil {
44 + t.Fatal(err)
45 + return nil, nil
46 + }
47 + return api, p
48 + }
49 +
50 + run := func(t *testing.T, ropts []opt.NameResolveOption) {
51 + t.Run("basic", func(t *testing.T) {
52 + api, p := init()
53 + e, err := api.Name().Publish(ctx, p)
54 + if err != nil {
55 + t.Fatal(err)
56 + }
57 +
58 + self, err := api.Key().Self(ctx)
59 + if err != nil {
60 + t.Fatal(err)
61 + }
62 +
63 + if e.Name() != self.ID().Pretty() {
64 + t.Errorf("expected e.Name to equal '%s', got '%s'", self.ID().Pretty(), e.Name())
65 + }
66 +
67 + if e.Value().String() != p.String() {
68 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
69 + }
70 +
71 + resPath, err := api.Name().Resolve(ctx, e.Name(), ropts...)
72 + if err != nil {
73 + t.Fatal(err)
74 + }
75 +
76 + if resPath.String() != p.String() {
77 + t.Errorf("expected paths to match, '%s'!='%s'", resPath.String(), p.String())
78 + }
79 + })
80 +
81 + t.Run("publishPath", func(t *testing.T) {
82 + api, p := init()
83 + e, err := api.Name().Publish(ctx, appendPath(p, "/test"))
84 + if err != nil {
85 + t.Fatal(err)
86 + }
87 +
88 + self, err := api.Key().Self(ctx)
89 + if err != nil {
90 + t.Fatal(err)
91 + }
92 +
93 + if e.Name() != self.ID().Pretty() {
94 + t.Errorf("expected e.Name to equal '%s', got '%s'", self.ID().Pretty(), e.Name())
95 + }
96 +
97 + if e.Value().String() != p.String()+"/test" {
98 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
99 + }
100 +
101 + resPath, err := api.Name().Resolve(ctx, e.Name(), ropts...)
102 + if err != nil {
103 + t.Fatal(err)
104 + }
105 +
106 + if resPath.String() != p.String()+"/test" {
107 + t.Errorf("expected paths to match, '%s'!='%s'", resPath.String(), p.String()+"/test")
108 + }
109 + })
110 +
111 + t.Run("revolvePath", func(t *testing.T) {
112 + api, p := init()
113 + e, err := api.Name().Publish(ctx, p)
114 + if err != nil {
115 + t.Fatal(err)
116 + }
117 +
118 + self, err := api.Key().Self(ctx)
119 + if err != nil {
120 + t.Fatal(err)
121 + }
122 +
123 + if e.Name() != self.ID().Pretty() {
124 + t.Errorf("expected e.Name to equal '%s', got '%s'", self.ID().Pretty(), e.Name())
125 + }
126 +
127 + if e.Value().String() != p.String() {
128 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
129 + }
130 +
131 + resPath, err := api.Name().Resolve(ctx, e.Name()+"/test", ropts...)
132 + if err != nil {
133 + t.Fatal(err)
134 + }
135 +
136 + if resPath.String() != p.String()+"/test" {
137 + t.Errorf("expected paths to match, '%s'!='%s'", resPath.String(), p.String()+"/test")
138 + }
139 + })
140 +
141 + t.Run("publishRevolvePath", func(t *testing.T) {
142 + api, p := init()
143 + e, err := api.Name().Publish(ctx, appendPath(p, "/a"))
144 + if err != nil {
145 + t.Fatal(err)
146 + }
147 +
148 + self, err := api.Key().Self(ctx)
149 + if err != nil {
150 + t.Fatal(err)
151 + }
152 +
153 + if e.Name() != self.ID().Pretty() {
154 + t.Errorf("expected e.Name to equal '%s', got '%s'", self.ID().Pretty(), e.Name())
155 + }
156 +
157 + if e.Value().String() != p.String()+"/a" {
158 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
159 + }
160 +
161 + resPath, err := api.Name().Resolve(ctx, e.Name()+"/b", ropts...)
162 + if err != nil {
163 + t.Fatal(err)
164 + }
165 +
166 + if resPath.String() != p.String()+"/a/b" {
167 + t.Errorf("expected paths to match, '%s'!='%s'", resPath.String(), p.String()+"/a/b")
168 + }
169 + })
170 + }
171 +
172 + t.Run("default", func(t *testing.T) {
173 + run(t, []opt.NameResolveOption{})
174 + })
175 +
176 + t.Run("nocache", func(t *testing.T) {
177 + run(t, []opt.NameResolveOption{opt.Name.Cache(false)})
178 + })
179 +}
180 +
181 +func TestBasicPublishResolveKey(t *testing.T) {
182 + ctx := context.Background()
183 + apis, err := makeAPISwarm(ctx, true, 5)
184 + if err != nil {
185 + t.Fatal(err)
186 + }
187 + api := apis[0]
188 +
189 + k, err := api.Key().Generate(ctx, "foo")
190 + if err != nil {
191 + t.Fatal(err)
192 + }
193 +
194 + p, err := addTestObject(ctx, api)
195 + if err != nil {
196 + t.Fatal(err)
197 + }
198 +
199 + e, err := api.Name().Publish(ctx, p, opt.Name.Key(k.Name()))
200 + if err != nil {
201 + t.Fatal(err)
202 + }
203 +
204 + if ipath.Join([]string{"/ipns", e.Name()}) != k.Path().String() {
205 + t.Errorf("expected e.Name to equal '%s', got '%s'", e.Name(), k.Path().String())
206 + }
207 +
208 + if e.Value().String() != p.String() {
209 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
210 + }
211 +
212 + resPath, err := api.Name().Resolve(ctx, e.Name())
213 + if err != nil {
214 + t.Fatal(err)
215 + }
216 +
217 + if resPath.String() != p.String() {
218 + t.Errorf("expected paths to match, '%s'!='%s'", resPath.String(), p.String())
219 + }
220 +}
221 +
222 +func TestBasicPublishResolveTimeout(t *testing.T) {
223 + t.Skip("ValidTime doesn't appear to work at this time resolution")
224 +
225 + ctx := context.Background()
226 + apis, err := makeAPISwarm(ctx, true, 5)
227 + if err != nil {
228 + t.Fatal(err)
229 + }
230 + api := apis[0]
231 + p, err := addTestObject(ctx, api)
232 + if err != nil {
233 + t.Fatal(err)
234 + }
235 +
236 + e, err := api.Name().Publish(ctx, p, opt.Name.ValidTime(time.Millisecond*100))
237 + if err != nil {
238 + t.Fatal(err)
239 + }
240 +
241 + self, err := api.Key().Self(ctx)
242 + if err != nil {
243 + t.Fatal(err)
244 + }
245 +
246 + if e.Name() != self.ID().Pretty() {
247 + t.Errorf("expected e.Name to equal '%s', got '%s'", self.ID().Pretty(), e.Name())
248 + }
249 +
250 + if e.Value().String() != p.String() {
251 + t.Errorf("expected paths to match, '%s'!='%s'", e.Value().String(), p.String())
252 + }
253 +
254 + time.Sleep(time.Second)
255 +
256 + _, err = api.Name().Resolve(ctx, e.Name())
257 + if err == nil {
258 + t.Fatal("Expected an error")
259 + }
260 +}
261 +
262 +//TODO: When swarm api is created, add multinode tests
core/coreiface/tests/object_test.go new
+427
@@ -0,0 +1,427 @@
1 +package tests_test
2 +
3 +import (
4 + "bytes"
5 + "context"
6 + "encoding/hex"
7 + "io/ioutil"
8 + "strings"
9 + "testing"
10 +
11 + "github.com/ipfs/go-ipfs/core/coreapi/interface"
12 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
13 +)
14 +
15 +func TestNew(t *testing.T) {
16 + ctx := context.Background()
17 + api, err := makeAPI(ctx)
18 + if err != nil {
19 + t.Fatal(err)
20 + }
21 +
22 + emptyNode, err := api.Object().New(ctx)
23 + if err != nil {
24 + t.Fatal(err)
25 + }
26 +
27 + dirNode, err := api.Object().New(ctx, opt.Object.Type("unixfs-dir"))
28 + if err != nil {
29 + t.Fatal(err)
30 + }
31 +
32 + if emptyNode.String() != "QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n" {
33 + t.Errorf("Unexpected emptyNode path: %s", emptyNode.String())
34 + }
35 +
36 + if dirNode.String() != "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn" {
37 + t.Errorf("Unexpected dirNode path: %s", dirNode.String())
38 + }
39 +}
40 +
41 +func TestObjectPut(t *testing.T) {
42 + ctx := context.Background()
43 + api, err := makeAPI(ctx)
44 + if err != nil {
45 + t.Fatal(err)
46 + }
47 +
48 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
49 + if err != nil {
50 + t.Fatal(err)
51 + }
52 +
53 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"YmFy"}`), opt.Object.DataType("base64")) //bar
54 + if err != nil {
55 + t.Fatal(err)
56 + }
57 +
58 + pbBytes, err := hex.DecodeString("0a0362617a")
59 + if err != nil {
60 + t.Fatal(err)
61 + }
62 +
63 + p3, err := api.Object().Put(ctx, bytes.NewReader(pbBytes), opt.Object.InputEnc("protobuf"))
64 + if err != nil {
65 + t.Fatal(err)
66 + }
67 +
68 + if p1.String() != "/ipfs/QmQeGyS87nyijii7kFt1zbe4n2PsXTFimzsdxyE9qh9TST" {
69 + t.Errorf("unexpected path: %s", p1.String())
70 + }
71 +
72 + if p2.String() != "/ipfs/QmNeYRbCibmaMMK6Du6ChfServcLqFvLJF76PzzF76SPrZ" {
73 + t.Errorf("unexpected path: %s", p2.String())
74 + }
75 +
76 + if p3.String() != "/ipfs/QmZreR7M2t7bFXAdb1V5FtQhjk4t36GnrvueLJowJbQM9m" {
77 + t.Errorf("unexpected path: %s", p3.String())
78 + }
79 +}
80 +
81 +func TestObjectGet(t *testing.T) {
82 + ctx := context.Background()
83 + api, err := makeAPI(ctx)
84 + if err != nil {
85 + t.Fatal(err)
86 + }
87 +
88 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
89 + if err != nil {
90 + t.Fatal(err)
91 + }
92 +
93 + nd, err := api.Object().Get(ctx, p1)
94 + if err != nil {
95 + t.Fatal(err)
96 + }
97 +
98 + if string(nd.RawData()[len(nd.RawData())-3:]) != "foo" {
99 + t.Fatal("got non-matching data")
100 + }
101 +}
102 +
103 +func TestObjectData(t *testing.T) {
104 + ctx := context.Background()
105 + api, err := makeAPI(ctx)
106 + if err != nil {
107 + t.Fatal(err)
108 + }
109 +
110 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
111 + if err != nil {
112 + t.Fatal(err)
113 + }
114 +
115 + r, err := api.Object().Data(ctx, p1)
116 + if err != nil {
117 + t.Fatal(err)
118 + }
119 +
120 + data, err := ioutil.ReadAll(r)
121 + if err != nil {
122 + t.Fatal(err)
123 + }
124 +
125 + if string(data) != "foo" {
126 + t.Fatal("got non-matching data")
127 + }
128 +}
129 +
130 +func TestObjectLinks(t *testing.T) {
131 + ctx := context.Background()
132 + api, err := makeAPI(ctx)
133 + if err != nil {
134 + t.Fatal(err)
135 + }
136 +
137 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
138 + if err != nil {
139 + t.Fatal(err)
140 + }
141 +
142 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Links":[{"Name":"bar", "Hash":"`+p1.Cid().String()+`"}]}`))
143 + if err != nil {
144 + t.Fatal(err)
145 + }
146 +
147 + links, err := api.Object().Links(ctx, p2)
148 + if err != nil {
149 + t.Fatal(err)
150 + }
151 +
152 + if len(links) != 1 {
153 + t.Errorf("unexpected number of links: %d", len(links))
154 + }
155 +
156 + if links[0].Cid.String() != p1.Cid().String() {
157 + t.Fatal("cids didn't batch")
158 + }
159 +
160 + if links[0].Name != "bar" {
161 + t.Fatal("unexpected link name")
162 + }
163 +}
164 +
165 +func TestObjectStat(t *testing.T) {
166 + ctx := context.Background()
167 + api, err := makeAPI(ctx)
168 + if err != nil {
169 + t.Fatal(err)
170 + }
171 +
172 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
173 + if err != nil {
174 + t.Fatal(err)
175 + }
176 +
177 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bazz", "Links":[{"Name":"bar", "Hash":"`+p1.Cid().String()+`", "Size":3}]}`))
178 + if err != nil {
179 + t.Fatal(err)
180 + }
181 +
182 + stat, err := api.Object().Stat(ctx, p2)
183 + if err != nil {
184 + t.Fatal(err)
185 + }
186 +
187 + if stat.Cid.String() != p2.Cid().String() {
188 + t.Error("unexpected stat.Cid")
189 + }
190 +
191 + if stat.NumLinks != 1 {
192 + t.Errorf("unexpected stat.NumLinks")
193 + }
194 +
195 + if stat.BlockSize != 51 {
196 + t.Error("unexpected stat.BlockSize")
197 + }
198 +
199 + if stat.LinksSize != 47 {
200 + t.Errorf("unexpected stat.LinksSize: %d", stat.LinksSize)
201 + }
202 +
203 + if stat.DataSize != 4 {
204 + t.Error("unexpected stat.DataSize")
205 + }
206 +
207 + if stat.CumulativeSize != 54 {
208 + t.Error("unexpected stat.DataSize")
209 + }
210 +}
211 +
212 +func TestObjectAddLink(t *testing.T) {
213 + ctx := context.Background()
214 + api, err := makeAPI(ctx)
215 + if err != nil {
216 + t.Fatal(err)
217 + }
218 +
219 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
220 + if err != nil {
221 + t.Fatal(err)
222 + }
223 +
224 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bazz", "Links":[{"Name":"bar", "Hash":"`+p1.Cid().String()+`", "Size":3}]}`))
225 + if err != nil {
226 + t.Fatal(err)
227 + }
228 +
229 + p3, err := api.Object().AddLink(ctx, p2, "abc", p2)
230 + if err != nil {
231 + t.Fatal(err)
232 + }
233 +
234 + links, err := api.Object().Links(ctx, p3)
235 + if err != nil {
236 + t.Fatal(err)
237 + }
238 +
239 + if len(links) != 2 {
240 + t.Errorf("unexpected number of links: %d", len(links))
241 + }
242 +
243 + if links[0].Name != "abc" {
244 + t.Errorf("unexpected link 0 name: %s", links[0].Name)
245 + }
246 +
247 + if links[1].Name != "bar" {
248 + t.Errorf("unexpected link 1 name: %s", links[1].Name)
249 + }
250 +}
251 +
252 +func TestObjectAddLinkCreate(t *testing.T) {
253 + ctx := context.Background()
254 + api, err := makeAPI(ctx)
255 + if err != nil {
256 + t.Fatal(err)
257 + }
258 +
259 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
260 + if err != nil {
261 + t.Fatal(err)
262 + }
263 +
264 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bazz", "Links":[{"Name":"bar", "Hash":"`+p1.Cid().String()+`", "Size":3}]}`))
265 + if err != nil {
266 + t.Fatal(err)
267 + }
268 +
269 + p3, err := api.Object().AddLink(ctx, p2, "abc/d", p2)
270 + if err == nil {
271 + t.Fatal("expected an error")
272 + }
273 + if err.Error() != "no link by that name" {
274 + t.Fatalf("unexpected error: %s", err.Error())
275 + }
276 +
277 + p3, err = api.Object().AddLink(ctx, p2, "abc/d", p2, opt.Object.Create(true))
278 + if err != nil {
279 + t.Fatal(err)
280 + }
281 +
282 + links, err := api.Object().Links(ctx, p3)
283 + if err != nil {
284 + t.Fatal(err)
285 + }
286 +
287 + if len(links) != 2 {
288 + t.Errorf("unexpected number of links: %d", len(links))
289 + }
290 +
291 + if links[0].Name != "abc" {
292 + t.Errorf("unexpected link 0 name: %s", links[0].Name)
293 + }
294 +
295 + if links[1].Name != "bar" {
296 + t.Errorf("unexpected link 1 name: %s", links[1].Name)
297 + }
298 +}
299 +
300 +func TestObjectRmLink(t *testing.T) {
301 + ctx := context.Background()
302 + api, err := makeAPI(ctx)
303 + if err != nil {
304 + t.Fatal(err)
305 + }
306 +
307 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
308 + if err != nil {
309 + t.Fatal(err)
310 + }
311 +
312 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bazz", "Links":[{"Name":"bar", "Hash":"`+p1.Cid().String()+`", "Size":3}]}`))
313 + if err != nil {
314 + t.Fatal(err)
315 + }
316 +
317 + p3, err := api.Object().RmLink(ctx, p2, "bar")
318 + if err != nil {
319 + t.Fatal(err)
320 + }
321 +
322 + links, err := api.Object().Links(ctx, p3)
323 + if err != nil {
324 + t.Fatal(err)
325 + }
326 +
327 + if len(links) != 0 {
328 + t.Errorf("unexpected number of links: %d", len(links))
329 + }
330 +}
331 +
332 +func TestObjectAddData(t *testing.T) {
333 + ctx := context.Background()
334 + api, err := makeAPI(ctx)
335 + if err != nil {
336 + t.Fatal(err)
337 + }
338 +
339 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
340 + if err != nil {
341 + t.Fatal(err)
342 + }
343 +
344 + p2, err := api.Object().AppendData(ctx, p1, strings.NewReader("bar"))
345 + if err != nil {
346 + t.Fatal(err)
347 + }
348 +
349 + r, err := api.Object().Data(ctx, p2)
350 + if err != nil {
351 + t.Fatal(err)
352 + }
353 +
354 + data, err := ioutil.ReadAll(r)
355 +
356 + if string(data) != "foobar" {
357 + t.Error("unexpected data")
358 + }
359 +}
360 +
361 +func TestObjectSetData(t *testing.T) {
362 + ctx := context.Background()
363 + api, err := makeAPI(ctx)
364 + if err != nil {
365 + t.Fatal(err)
366 + }
367 +
368 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
369 + if err != nil {
370 + t.Fatal(err)
371 + }
372 +
373 + p2, err := api.Object().SetData(ctx, p1, strings.NewReader("bar"))
374 + if err != nil {
375 + t.Fatal(err)
376 + }
377 +
378 + r, err := api.Object().Data(ctx, p2)
379 + if err != nil {
380 + t.Fatal(err)
381 + }
382 +
383 + data, err := ioutil.ReadAll(r)
384 +
385 + if string(data) != "bar" {
386 + t.Error("unexpected data")
387 + }
388 +}
389 +
390 +func TestDiffTest(t *testing.T) {
391 + ctx := context.Background()
392 + api, err := makeAPI(ctx)
393 + if err != nil {
394 + t.Fatal(err)
395 + }
396 +
397 + p1, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"foo"}`))
398 + if err != nil {
399 + t.Fatal(err)
400 + }
401 +
402 + p2, err := api.Object().Put(ctx, strings.NewReader(`{"Data":"bar"}`))
403 + if err != nil {
404 + t.Fatal(err)
405 + }
406 +
407 + changes, err := api.Object().Diff(ctx, p1, p2)
408 + if err != nil {
409 + t.Fatal(err)
410 + }
411 +
412 + if len(changes) != 1 {
413 + t.Fatal("unexpected changes len")
414 + }
415 +
416 + if changes[0].Type != iface.DiffMod {
417 + t.Fatal("unexpected change type")
418 + }
419 +
420 + if changes[0].Before.String() != p1.String() {
421 + t.Fatal("unexpected before path")
422 + }
423 +
424 + if changes[0].After.String() != p2.String() {
425 + t.Fatal("unexpected before path")
426 + }
427 +}
core/coreiface/tests/path_test.go new
+154
@@ -0,0 +1,154 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "strings"
6 + "testing"
7 +
8 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
9 + "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
10 +)
11 +
12 +func TestMutablePath(t *testing.T) {
13 + ctx := context.Background()
14 + api, err := makeAPI(ctx)
15 + if err != nil {
16 + t.Fatal(err)
17 + }
18 +
19 + // get self /ipns path
20 + keys, err := api.Key().List(ctx)
21 + if err != nil {
22 + t.Fatal(err)
23 + }
24 +
25 + if !keys[0].Path().Mutable() {
26 + t.Error("expected self /ipns path to be mutable")
27 + }
28 +
29 + blk, err := api.Block().Put(ctx, strings.NewReader(`foo`))
30 + if err != nil {
31 + t.Error(err)
32 + }
33 +
34 + if blk.Path().Mutable() {
35 + t.Error("expected /ipld path to be immutable")
36 + }
37 +}
38 +
39 +func TestPathRemainder(t *testing.T) {
40 + ctx := context.Background()
41 + api, err := makeAPI(ctx)
42 + if err != nil {
43 + t.Fatal(err)
44 + }
45 +
46 + obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
47 + if err != nil {
48 + t.Fatal(err)
49 + }
50 +
51 + p1, err := coreiface.ParsePath(obj.String() + "/foo/bar")
52 + if err != nil {
53 + t.Error(err)
54 + }
55 +
56 + rp1, err := api.ResolvePath(ctx, p1)
57 + if err != nil {
58 + t.Fatal(err)
59 + }
60 +
61 + if rp1.Remainder() != "foo/bar" {
62 + t.Error("expected to get path remainder")
63 + }
64 +}
65 +
66 +func TestEmptyPathRemainder(t *testing.T) {
67 + ctx := context.Background()
68 + api, err := makeAPI(ctx)
69 + if err != nil {
70 + t.Fatal(err)
71 + }
72 +
73 + obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
74 + if err != nil {
75 + t.Fatal(err)
76 + }
77 +
78 + if obj.Remainder() != "" {
79 + t.Error("expected the resolved path to not have a remainder")
80 + }
81 +
82 + p1, err := coreiface.ParsePath(obj.String())
83 + if err != nil {
84 + t.Error(err)
85 + }
86 +
87 + rp1, err := api.ResolvePath(ctx, p1)
88 + if err != nil {
89 + t.Fatal(err)
90 + }
91 +
92 + if rp1.Remainder() != "" {
93 + t.Error("expected the resolved path to not have a remainder")
94 + }
95 +}
96 +
97 +func TestInvalidPathRemainder(t *testing.T) {
98 + ctx := context.Background()
99 + api, err := makeAPI(ctx)
100 + if err != nil {
101 + t.Fatal(err)
102 + }
103 +
104 + obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
105 + if err != nil {
106 + t.Fatal(err)
107 + }
108 +
109 + p1, err := coreiface.ParsePath(obj.String() + "/bar/baz")
110 + if err != nil {
111 + t.Error(err)
112 + }
113 +
114 + _, err = api.ResolvePath(ctx, p1)
115 + if err == nil || err.Error() != "no such link found" {
116 + t.Fatalf("unexpected error: %s", err)
117 + }
118 +}
119 +
120 +func TestPathRoot(t *testing.T) {
121 + ctx := context.Background()
122 + api, err := makeAPI(ctx)
123 + if err != nil {
124 + t.Fatal(err)
125 + }
126 +
127 + blk, err := api.Block().Put(ctx, strings.NewReader(`foo`), options.Block.Format("raw"))
128 + if err != nil {
129 + t.Error(err)
130 + }
131 +
132 + obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"/": "`+blk.Path().Cid().String()+`"}}`))
133 + if err != nil {
134 + t.Fatal(err)
135 + }
136 +
137 + p1, err := coreiface.ParsePath(obj.String() + "/foo")
138 + if err != nil {
139 + t.Error(err)
140 + }
141 +
142 + rp, err := api.ResolvePath(ctx, p1)
143 + if err != nil {
144 + t.Fatal(err)
145 + }
146 +
147 + if rp.Root().String() != obj.Cid().String() {
148 + t.Error("unexpected path root")
149 + }
150 +
151 + if rp.Cid().String() != blk.Path().Cid().String() {
152 + t.Error("unexpected path cid")
153 + }
154 +}
core/coreiface/tests/pin_test.go new
+214
@@ -0,0 +1,214 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "strings"
6 + "testing"
7 +
8 + opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
9 +)
10 +
11 +func TestPinAdd(t *testing.T) {
12 + ctx := context.Background()
13 + api, err := makeAPI(ctx)
14 + if err != nil {
15 + t.Error(err)
16 + }
17 +
18 + p, err := api.Unixfs().Add(ctx, strFile("foo")())
19 + if err != nil {
20 + t.Error(err)
21 + }
22 +
23 + err = api.Pin().Add(ctx, p)
24 + if err != nil {
25 + t.Error(err)
26 + }
27 +}
28 +
29 +func TestPinSimple(t *testing.T) {
30 + ctx := context.Background()
31 + api, err := makeAPI(ctx)
32 + if err != nil {
33 + t.Error(err)
34 + }
35 +
36 + p, err := api.Unixfs().Add(ctx, strFile("foo")())
37 + if err != nil {
38 + t.Error(err)
39 + }
40 +
41 + err = api.Pin().Add(ctx, p)
42 + if err != nil {
43 + t.Error(err)
44 + }
45 +
46 + list, err := api.Pin().Ls(ctx)
47 + if err != nil {
48 + t.Fatal(err)
49 + }
50 +
51 + if len(list) != 1 {
52 + t.Errorf("unexpected pin list len: %d", len(list))
53 + }
54 +
55 + if list[0].Path().Cid().String() != p.Cid().String() {
56 + t.Error("paths don't match")
57 + }
58 +
59 + if list[0].Type() != "recursive" {
60 + t.Error("unexpected pin type")
61 + }
62 +
63 + err = api.Pin().Rm(ctx, p)
64 + if err != nil {
65 + t.Fatal(err)
66 + }
67 +
68 + list, err = api.Pin().Ls(ctx)
69 + if err != nil {
70 + t.Fatal(err)
71 + }
72 +
73 + if len(list) != 0 {
74 + t.Errorf("unexpected pin list len: %d", len(list))
75 + }
76 +}
77 +
78 +func TestPinRecursive(t *testing.T) {
79 + ctx := context.Background()
80 + api, err := makeAPI(ctx)
81 + if err != nil {
82 + t.Error(err)
83 + }
84 +
85 + p0, err := api.Unixfs().Add(ctx, strFile("foo")())
86 + if err != nil {
87 + t.Error(err)
88 + }
89 +
90 + p1, err := api.Unixfs().Add(ctx, strFile("bar")())
91 + if err != nil {
92 + t.Error(err)
93 + }
94 +
95 + p2, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+p0.Cid().String()+`"}}`))
96 + if err != nil {
97 + t.Error(err)
98 + }
99 +
100 + p3, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+p1.Cid().String()+`"}}`))
101 + if err != nil {
102 + t.Error(err)
103 + }
104 +
105 + err = api.Pin().Add(ctx, p2)
106 + if err != nil {
107 + t.Error(err)
108 + }
109 +
110 + err = api.Pin().Add(ctx, p3, opt.Pin.Recursive(false))
111 + if err != nil {
112 + t.Error(err)
113 + }
114 +
115 + list, err := api.Pin().Ls(ctx)
116 + if err != nil {
117 + t.Fatal(err)
118 + }
119 +
120 + if len(list) != 3 {
121 + t.Errorf("unexpected pin list len: %d", len(list))
122 + }
123 +
124 + list, err = api.Pin().Ls(ctx, opt.Pin.Type.Direct())
125 + if err != nil {
126 + t.Fatal(err)
127 + }
128 +
129 + if len(list) != 1 {
130 + t.Errorf("unexpected pin list len: %d", len(list))
131 + }
132 +
133 + if list[0].Path().String() != p3.String() {
134 + t.Error("unexpected path")
135 + }
136 +
137 + list, err = api.Pin().Ls(ctx, opt.Pin.Type.Recursive())
138 + if err != nil {
139 + t.Fatal(err)
140 + }
141 +
142 + if len(list) != 1 {
143 + t.Errorf("unexpected pin list len: %d", len(list))
144 + }
145 +
146 + if list[0].Path().String() != p2.String() {
147 + t.Error("unexpected path")
148 + }
149 +
150 + list, err = api.Pin().Ls(ctx, opt.Pin.Type.Indirect())
151 + if err != nil {
152 + t.Fatal(err)
153 + }
154 +
155 + if len(list) != 1 {
156 + t.Errorf("unexpected pin list len: %d", len(list))
157 + }
158 +
159 + if list[0].Path().Cid().String() != p0.Cid().String() {
160 + t.Error("unexpected path")
161 + }
162 +
163 + res, err := api.Pin().Verify(ctx)
164 + if err != nil {
165 + t.Fatal(err)
166 + }
167 + n := 0
168 + for r := range res {
169 + if !r.Ok() {
170 + t.Error("expected pin to be ok")
171 + }
172 + n++
173 + }
174 +
175 + if n != 1 {
176 + t.Errorf("unexpected verify result count: %d", n)
177 + }
178 +
179 + //TODO: figure out a way to test verify without touching IpfsNode
180 + /*
181 + err = api.Block().Rm(ctx, p0, opt.Block.Force(true))
182 + if err != nil {
183 + t.Fatal(err)
184 + }
185 +
186 + res, err = api.Pin().Verify(ctx)
187 + if err != nil {
188 + t.Fatal(err)
189 + }
190 + n = 0
191 + for r := range res {
192 + if r.Ok() {
193 + t.Error("expected pin to not be ok")
194 + }
195 +
196 + if len(r.BadNodes()) != 1 {
197 + t.Fatalf("unexpected badNodes len")
198 + }
199 +
200 + if r.BadNodes()[0].Path().Cid().String() != p0.Cid().String() {
201 + t.Error("unexpected badNode path")
202 + }
203 +
204 + if r.BadNodes()[0].Err().Error() != "merkledag: not found" {
205 + t.Errorf("unexpected badNode error: %s", r.BadNodes()[0].Err().Error())
206 + }
207 + n++
208 + }
209 +
210 + if n != 1 {
211 + t.Errorf("unexpected verify result count: %d", n)
212 + }
213 + */
214 +}
core/coreiface/tests/pubsub_test.go new
+106
@@ -0,0 +1,106 @@
1 +package tests_test
2 +
3 +import (
4 + "context"
5 + "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
6 + "testing"
7 + "time"
8 +)
9 +
10 +func TestBasicPubSub(t *testing.T) {
11 + ctx, cancel := context.WithCancel(context.Background())
12 + defer cancel()
13 +
14 + apis, err := makeAPISwarm(ctx, true, 2)
15 + if err != nil {
16 + t.Fatal(err)
17 + }
18 +
19 + sub, err := apis[0].PubSub().Subscribe(ctx, "testch")
20 + if err != nil {
21 + t.Fatal(err)
22 + }
23 +
24 + go func() {
25 + tick := time.Tick(100 * time.Millisecond)
26 +
27 + for {
28 + err = apis[1].PubSub().Publish(ctx, "testch", []byte("hello world"))
29 + if err != nil {
30 + t.Fatal(err)
31 + }
32 + select {
33 + case <-tick:
34 + case <-ctx.Done():
35 + return
36 + }
37 + }
38 + }()
39 +
40 + m, err := sub.Next(ctx)
41 + if err != nil {
42 + t.Fatal(err)
43 + }
44 +
45 + if string(m.Data()) != "hello world" {
46 + t.Errorf("got invalid data: %s", string(m.Data()))
47 + }
48 +
49 + self1, err := apis[1].Key().Self(ctx)
50 + if err != nil {
51 + t.Fatal(err)
52 + }
53 +
54 + if m.From() != self1.ID() {
55 + t.Errorf("m.From didn't match")
56 + }
57 +
58 + peers, err := apis[1].PubSub().Peers(ctx, options.PubSub.Topic("testch"))
59 + if err != nil {
60 + t.Fatal(err)
61 + }
62 +
63 + if len(peers) != 1 {
64 + t.Fatalf("got incorrect number of peers: %d", len(peers))
65 + }
66 +
67 + self0, err := apis[0].Key().Self(ctx)
68 + if err != nil {
69 + t.Fatal(err)
70 + }
71 +
72 + if peers[0] != self0.ID() {
73 + t.Errorf("peer didn't match")
74 + }
75 +
76 + peers, err = apis[1].PubSub().Peers(ctx, options.PubSub.Topic("nottestch"))
77 + if err != nil {
78 + t.Fatal(err)
79 + }
80 +
81 + if len(peers) != 0 {
82 + t.Fatalf("got incorrect number of peers: %d", len(peers))
83 + }
84 +
85 + topics, err := apis[0].PubSub().Ls(ctx)
86 + if err != nil {
87 + t.Fatal(err)
88 + }
89 +
90 + if len(topics) != 1 {
91 + t.Fatalf("got incorrect number of topics: %d", len(peers))
92 + }
93 +
94 + if topics[0] != "testch" {
95 + t.Errorf("topic didn't match")
96 + }
97 +
98 + topics, err = apis[1].PubSub().Ls(ctx)
99 + if err != nil {
100 + t.Fatal(err)
101 + }
102 +
103 + if len(topics) != 0 {
104 + t.Fatalf("got incorrect number of topics: %d", len(peers))
105 + }
106 +}
core/coreiface/tests/unixfs_test.go new
+963
@@ -0,0 +1,963 @@
1 +package tests_test
2 +
3 +import (
4 + "bytes"
5 + "context"
6 + "encoding/base64"
7 + "fmt"
8 + "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
9 + "io"
10 + "io/ioutil"
11 + "math"
12 + "os"
13 + "strconv"
14 + "strings"
15 + "sync"
16 + "testing"
17 +
18 + "github.com/ipfs/go-ipfs/core"
19 + "github.com/ipfs/go-ipfs/core/coreapi"
20 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
21 + "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
22 + mock "github.com/ipfs/go-ipfs/core/mock"
23 + "github.com/ipfs/go-ipfs/keystore"
24 + "github.com/ipfs/go-ipfs/repo"
25 +
26 + ci "gx/ipfs/QmNiJiXwWE3kRhZrC5ej3kSjWHm337pYfhjLGSCDNKJP2s/go-libp2p-crypto"
27 + "gx/ipfs/QmRBaUEQEeFWywfrZJ64QgsmvcqgLSK3VbvGMR2NM2Edpf/go-libp2p/p2p/net/mock"
28 + cbor "gx/ipfs/QmRoARq3nkUb13HSKZGepCZSWe5GrVPwx7xURJGZ7KWv9V/go-ipld-cbor"
29 + "gx/ipfs/QmXWZCd8jfaHmt4UDSnjKmGcrQMw95bDGWqEeVLVJjoANX/go-ipfs-files"
30 + "gx/ipfs/QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY/go-libp2p-peer"
31 + pstore "gx/ipfs/QmZ9zH2FnLcxv1xyzFeUpDUeo55xEhZQHgveZijcxr7TLj/go-libp2p-peerstore"
32 + "gx/ipfs/Qmbvw7kpSM2p6rbQ57WGRhhqNfCiNGW6EKH4xgHLw4bsnB/go-unixfs"
33 + "gx/ipfs/QmcZfkbgwwwH5ZLTQRHkSQBDiDqd3skY2eU6MZRgWuXcse/go-ipfs-config"
34 + mdag "gx/ipfs/QmdV35UHnL1FM52baPkeUo6u7Fxm2CRUkPTLRPxeF8a4Ap/go-merkledag"
35 + mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
36 + "gx/ipfs/Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM/go-datastore"
37 + syncds "gx/ipfs/Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM/go-datastore/sync"
38 +)
39 +
40 +const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe"
41 +
42 +// `echo -n 'hello, world!' | ipfs add`
43 +var hello = "/ipfs/QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk"
44 +var helloStr = "hello, world!"
45 +
46 +// `echo -n | ipfs add`
47 +var emptyFile = "/ipfs/QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH"
48 +
49 +func makeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) {
50 + mn := mocknet.New(ctx)
51 +
52 + nodes := make([]*core.IpfsNode, n)
53 + apis := make([]coreiface.CoreAPI, n)
54 +
55 + for i := 0; i < n; i++ {
56 + var ident config.Identity
57 + if fullIdentity {
58 + sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
59 + if err != nil {
60 + return nil, err
61 + }
62 +
63 + id, err := peer.IDFromPublicKey(pk)
64 + if err != nil {
65 + return nil, err
66 + }
67 +
68 + kbytes, err := sk.Bytes()
69 + if err != nil {
70 + return nil, err
71 + }
72 +
73 + ident = config.Identity{
74 + PeerID: id.Pretty(),
75 + PrivKey: base64.StdEncoding.EncodeToString(kbytes),
76 + }
77 + } else {
78 + ident = config.Identity{
79 + PeerID: testPeerID,
80 + }
81 + }
82 +
83 + c := config.Config{}
84 + c.Addresses.Swarm = []string{fmt.Sprintf("/ip4/127.0.%d.1/tcp/4001", i)}
85 + c.Identity = ident
86 +
87 + r := &repo.Mock{
88 + C: c,
89 + D: syncds.MutexWrap(datastore.NewMapDatastore()),
90 + K: keystore.NewMemKeystore(),
91 + }
92 +
93 + node, err := core.NewNode(ctx, &core.BuildCfg{
94 + Repo: r,
95 + Host: mock.MockHostOption(mn),
96 + Online: fullIdentity,
97 + ExtraOpts: map[string]bool{
98 + "pubsub": true,
99 + },
100 + })
101 + if err != nil {
102 + return nil, err
103 + }
104 + nodes[i] = node
105 + apis[i], err = coreapi.NewCoreAPI(node)
106 + if err != nil {
107 + return nil, err
108 + }
109 + }
110 +
111 + err := mn.LinkAll()
112 + if err != nil {
113 + return nil, err
114 + }
115 +
116 + bsinf := core.BootstrapConfigWithPeers(
117 + []pstore.PeerInfo{
118 + nodes[0].Peerstore.PeerInfo(nodes[0].Identity),
119 + },
120 + )
121 +
122 + for _, n := range nodes[1:] {
123 + if err := n.Bootstrap(bsinf); err != nil {
124 + return nil, err
125 + }
126 + }
127 +
128 + return apis, nil
129 +}
130 +
131 +func makeAPI(ctx context.Context) (coreiface.CoreAPI, error) {
132 + api, err := makeAPISwarm(ctx, false, 1)
133 + if err != nil {
134 + return nil, err
135 + }
136 +
137 + return api[0], nil
138 +}
139 +
140 +func strFile(data string) func() files.Node {
141 + return func() files.Node {
142 + return files.NewBytesFile([]byte(data))
143 + }
144 +}
145 +
146 +func twoLevelDir() func() files.Node {
147 + return func() files.Node {
148 + return files.NewMapDirectory(map[string]files.Node{
149 + "abc": files.NewMapDirectory(map[string]files.Node{
150 + "def": files.NewBytesFile([]byte("world")),
151 + }),
152 +
153 + "bar": files.NewBytesFile([]byte("hello2")),
154 + "foo": files.NewBytesFile([]byte("hello1")),
155 + })
156 + }
157 +}
158 +
159 +func flatDir() files.Node {
160 + return files.NewMapDirectory(map[string]files.Node{
161 + "bar": files.NewBytesFile([]byte("hello2")),
162 + "foo": files.NewBytesFile([]byte("hello1")),
163 + })
164 +}
165 +
166 +func wrapped(name string) func(f files.Node) files.Node {
167 + return func(f files.Node) files.Node {
168 + return files.NewMapDirectory(map[string]files.Node{
169 + name: f,
170 + })
171 + }
172 +}
173 +
174 +func TestAdd(t *testing.T) {
175 + ctx := context.Background()
176 + api, err := makeAPI(ctx)
177 + if err != nil {
178 + t.Error(err)
179 + }
180 +
181 + p := func(h string) coreiface.ResolvedPath {
182 + c, err := cid.Parse(h)
183 + if err != nil {
184 + t.Fatal(err)
185 + }
186 + return coreiface.IpfsPath(c)
187 + }
188 +
189 + cases := []struct {
190 + name string
191 + data func() files.Node
192 + expect func(files.Node) files.Node
193 +
194 + apiOpts []options.ApiOption
195 +
196 + path string
197 + err string
198 +
199 + wrap string
200 +
201 + events []coreiface.AddEvent
202 +
203 + opts []options.UnixfsAddOption
204 + }{
205 + // Simple cases
206 + {
207 + name: "simpleAdd",
208 + data: strFile(helloStr),
209 + path: hello,
210 + opts: []options.UnixfsAddOption{},
211 + },
212 + {
213 + name: "addEmpty",
214 + data: strFile(""),
215 + path: emptyFile,
216 + },
217 + // CIDv1 version / rawLeaves
218 + {
219 + name: "addCidV1",
220 + data: strFile(helloStr),
221 + path: "/ipfs/zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd",
222 + opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(1)},
223 + },
224 + {
225 + name: "addCidV1NoLeaves",
226 + data: strFile(helloStr),
227 + path: "/ipfs/zdj7WY4GbN8NDbTW1dfCShAQNVovams2xhq9hVCx5vXcjvT8g",
228 + opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(1), options.Unixfs.RawLeaves(false)},
229 + },
230 + // Non sha256 hash vs CID
231 + {
232 + name: "addCidSha3",
233 + data: strFile(helloStr),
234 + path: "/ipfs/zb2wwnYtXBxpndNABjtYxWAPt3cwWNRnc11iT63fvkYV78iRb",
235 + opts: []options.UnixfsAddOption{options.Unixfs.Hash(mh.SHA3_256)},
236 + },
237 + {
238 + name: "addCidSha3Cid0",
239 + data: strFile(helloStr),
240 + err: "CIDv0 only supports sha2-256",
241 + opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(0), options.Unixfs.Hash(mh.SHA3_256)},
242 + },
243 + // Inline
244 + {
245 + name: "addInline",
246 + data: strFile(helloStr),
247 + path: "/ipfs/zaYomJdLndMku8P9LHngHB5w2CQ7NenLbv",
248 + opts: []options.UnixfsAddOption{options.Unixfs.Inline(true)},
249 + },
250 + {
251 + name: "addInlineLimit",
252 + data: strFile(helloStr),
253 + path: "/ipfs/zaYomJdLndMku8P9LHngHB5w2CQ7NenLbv",
254 + opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(32), options.Unixfs.Inline(true)},
255 + },
256 + {
257 + name: "addInlineZero",
258 + data: strFile(""),
259 + path: "/ipfs/z2yYDV",
260 + opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(0), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true)},
261 + },
262 + { //TODO: after coreapi add is used in `ipfs add`, consider making this default for inline
263 + name: "addInlineRaw",
264 + data: strFile(helloStr),
265 + path: "/ipfs/zj7Gr8AcBreqGEfrnR5kPFe",
266 + opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(32), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true)},
267 + },
268 + // Chunker / Layout
269 + {
270 + name: "addChunks",
271 + data: strFile(strings.Repeat("aoeuidhtns", 200)),
272 + path: "/ipfs/QmRo11d4QJrST47aaiGVJYwPhoNA4ihRpJ5WaxBWjWDwbX",
273 + opts: []options.UnixfsAddOption{options.Unixfs.Chunker("size-4")},
274 + },
275 + {
276 + name: "addChunksTrickle",
277 + data: strFile(strings.Repeat("aoeuidhtns", 200)),
278 + path: "/ipfs/QmNNhDGttafX3M1wKWixGre6PrLFGjnoPEDXjBYpTv93HP",
279 + opts: []options.UnixfsAddOption{options.Unixfs.Chunker("size-4"), options.Unixfs.Layout(options.TrickleLayout)},
280 + },
281 + // Local
282 + {
283 + name: "addLocal", // better cases in sharness
284 + data: strFile(helloStr),
285 + path: hello,
286 + apiOpts: []options.ApiOption{options.Api.Offline(true)},
287 + },
288 + {
289 + name: "hashOnly", // test (non)fetchability
290 + data: strFile(helloStr),
291 + path: hello,
292 + opts: []options.UnixfsAddOption{options.Unixfs.HashOnly(true)},
293 + },
294 + // multi file
295 + {
296 + name: "simpleDir",
297 + data: flatDir,
298 + wrap: "t",
299 + path: "/ipfs/QmRKGpFfR32FVXdvJiHfo4WJ5TDYBsM1P9raAp1p6APWSp",
300 + },
301 + {
302 + name: "twoLevelDir",
303 + data: twoLevelDir(),
304 + wrap: "t",
305 + path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
306 + },
307 + // wrapped
308 + {
309 + name: "addWrapped",
310 + path: "/ipfs/QmVE9rNpj5doj7XHzp5zMUxD7BJgXEqx4pe3xZ3JBReWHE",
311 + data: func() files.Node {
312 + return files.NewBytesFile([]byte(helloStr))
313 + },
314 + wrap: "foo",
315 + expect: wrapped("foo"),
316 + opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
317 + },
318 + {
319 + name: "addNotWrappedDirFile",
320 + path: hello,
321 + data: func() files.Node {
322 + return files.NewBytesFile([]byte(helloStr))
323 + },
324 + wrap: "foo",
325 + },
326 + {
327 + name: "stdinWrapped",
328 + path: "/ipfs/QmU3r81oZycjHS9oaSHw37ootMFuFUw1DvMLKXPsezdtqU",
329 + data: func() files.Node {
330 + return files.NewBytesFile([]byte(helloStr))
331 + },
332 + expect: func(files.Node) files.Node {
333 + return files.NewMapDirectory(map[string]files.Node{
334 + "QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk": files.NewBytesFile([]byte(helloStr)),
335 + })
336 + },
337 + opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
338 + },
339 + {
340 + name: "stdinNamed",
341 + path: "/ipfs/QmQ6cGBmb3ZbdrQW1MRm1RJnYnaxCqfssz7CrTa9NEhQyS",
342 + data: func() files.Node {
343 + rf, err := files.NewReaderPathFile(os.Stdin.Name(), ioutil.NopCloser(strings.NewReader(helloStr)), nil)
344 + if err != nil {
345 + panic(err)
346 + }
347 +
348 + return rf
349 + },
350 + expect: func(files.Node) files.Node {
351 + return files.NewMapDirectory(map[string]files.Node{
352 + "test": files.NewBytesFile([]byte(helloStr)),
353 + })
354 + },
355 + opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true), options.Unixfs.StdinName("test")},
356 + },
357 + {
358 + name: "twoLevelDirWrapped",
359 + data: twoLevelDir(),
360 + wrap: "t",
361 + expect: wrapped("t"),
362 + path: "/ipfs/QmPwsL3T5sWhDmmAWZHAzyjKtMVDS9a11aHNRqb3xoVnmg",
363 + opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
364 + },
365 + {
366 + name: "twoLevelInlineHash",
367 + data: twoLevelDir(),
368 + wrap: "t",
369 + expect: wrapped("t"),
370 + path: "/ipfs/zBunoruKoyCHKkALNSWxDvj4L7yuQnMgQ4hUa9j1Z64tVcDEcu6Zdetyu7eeFCxMPfxb7YJvHeFHoFoHMkBUQf6vfdhmi",
371 + opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true), options.Unixfs.Hash(mh.SHA3)},
372 + },
373 + // hidden
374 + {
375 + name: "hiddenFiles",
376 + data: func() files.Node {
377 + return files.NewMapDirectory(map[string]files.Node{
378 + ".bar": files.NewBytesFile([]byte("hello2")),
379 + "bar": files.NewBytesFile([]byte("hello2")),
380 + "foo": files.NewBytesFile([]byte("hello1")),
381 + })
382 + },
383 + wrap: "t",
384 + path: "/ipfs/QmehGvpf2hY196MzDFmjL8Wy27S4jbgGDUAhBJyvXAwr3g",
385 + opts: []options.UnixfsAddOption{options.Unixfs.Hidden(true)},
386 + },
387 + {
388 + name: "hiddenFileAlwaysAdded",
389 + data: func() files.Node {
390 + return files.NewBytesFile([]byte(helloStr))
391 + },
392 + wrap: ".foo",
393 + path: hello,
394 + },
395 + {
396 + name: "hiddenFilesNotAdded",
397 + data: func() files.Node {
398 + return files.NewMapDirectory(map[string]files.Node{
399 + ".bar": files.NewBytesFile([]byte("hello2")),
400 + "bar": files.NewBytesFile([]byte("hello2")),
401 + "foo": files.NewBytesFile([]byte("hello1")),
402 + })
403 + },
404 + expect: func(files.Node) files.Node {
405 + return flatDir()
406 + },
407 + wrap: "t",
408 + path: "/ipfs/QmRKGpFfR32FVXdvJiHfo4WJ5TDYBsM1P9raAp1p6APWSp",
409 + opts: []options.UnixfsAddOption{options.Unixfs.Hidden(false)},
410 + },
411 + // Events / Progress
412 + {
413 + name: "simpleAddEvent",
414 + data: strFile(helloStr),
415 + path: "/ipfs/zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd",
416 + events: []coreiface.AddEvent{
417 + {Name: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Path: p("zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd"), Size: strconv.Itoa(len(helloStr))},
418 + },
419 + opts: []options.UnixfsAddOption{options.Unixfs.RawLeaves(true)},
420 + },
421 + {
422 + name: "silentAddEvent",
423 + data: twoLevelDir(),
424 + path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
425 + events: []coreiface.AddEvent{
426 + {Name: "t/abc", Path: p("QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt"), Size: "62"},
427 + {Name: "t", Path: p("QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr"), Size: "229"},
428 + },
429 + wrap: "t",
430 + opts: []options.UnixfsAddOption{options.Unixfs.Silent(true)},
431 + },
432 + {
433 + name: "dirAddEvents",
434 + data: twoLevelDir(),
435 + path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
436 + events: []coreiface.AddEvent{
437 + {Name: "t/abc/def", Path: p("QmNyJpQkU1cEkBwMDhDNFstr42q55mqG5GE5Mgwug4xyGk"), Size: "13"},
438 + {Name: "t/bar", Path: p("QmS21GuXiRMvJKHos4ZkEmQDmRBqRaF5tQS2CQCu2ne9sY"), Size: "14"},
439 + {Name: "t/foo", Path: p("QmfAjGiVpTN56TXi6SBQtstit5BEw3sijKj1Qkxn6EXKzJ"), Size: "14"},
440 + {Name: "t/abc", Path: p("QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt"), Size: "62"},
441 + {Name: "t", Path: p("QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr"), Size: "229"},
442 + },
443 + wrap: "t",
444 + },
445 + {
446 + name: "progress1M",
447 + data: func() files.Node {
448 + return files.NewReaderFile(bytes.NewReader(bytes.Repeat([]byte{0}, 1000000)))
449 + },
450 + path: "/ipfs/QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD",
451 + events: []coreiface.AddEvent{
452 + {Name: "", Bytes: 262144},
453 + {Name: "", Bytes: 524288},
454 + {Name: "", Bytes: 786432},
455 + {Name: "", Bytes: 1000000},
456 + {Name: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Path: p("QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD"), Size: "1000256"},
457 + },
458 + wrap: "",
459 + opts: []options.UnixfsAddOption{options.Unixfs.Progress(true)},
460 + },
461 + }
462 +
463 + for _, testCase := range cases {
464 + t.Run(testCase.name, func(t *testing.T) {
465 + ctx, cancel := context.WithCancel(ctx)
466 + defer cancel()
467 +
468 + // recursive logic
469 +
470 + data := testCase.data()
471 + if testCase.wrap != "" {
472 + data = files.NewMapDirectory(map[string]files.Node{
473 + testCase.wrap: data,
474 + })
475 + }
476 +
477 + // handle events if relevant to test case
478 +
479 + opts := testCase.opts
480 + eventOut := make(chan interface{})
481 + var evtWg sync.WaitGroup
482 + if len(testCase.events) > 0 {
483 + opts = append(opts, options.Unixfs.Events(eventOut))
484 + evtWg.Add(1)
485 +
486 + go func() {
487 + defer evtWg.Done()
488 + expected := testCase.events
489 +
490 + for evt := range eventOut {
491 + event, ok := evt.(*coreiface.AddEvent)
492 + if !ok {
493 + t.Fatal("unexpected event type")
494 + }
495 +
496 + if len(expected) < 1 {
497 + t.Fatal("got more events than expected")
498 + }
499 +
500 + if expected[0].Size != event.Size {
501 + t.Errorf("Event.Size didn't match, %s != %s", expected[0].Size, event.Size)
502 + }
503 +
504 + if expected[0].Name != event.Name {
505 + t.Errorf("Event.Name didn't match, %s != %s", expected[0].Name, event.Name)
506 + }
507 +
508 + if expected[0].Path != nil && event.Path != nil {
509 + if expected[0].Path.Cid().String() != event.Path.Cid().String() {
510 + t.Errorf("Event.Hash didn't match, %s != %s", expected[0].Path, event.Path)
511 + }
512 + } else if event.Path != expected[0].Path {
513 + t.Errorf("Event.Hash didn't match, %s != %s", expected[0].Path, event.Path)
514 + }
515 + if expected[0].Bytes != event.Bytes {
516 + t.Errorf("Event.Bytes didn't match, %d != %d", expected[0].Bytes, event.Bytes)
517 + }
518 +
519 + expected = expected[1:]
520 + }
521 +
522 + if len(expected) > 0 {
523 + t.Fatalf("%d event(s) didn't arrive", len(expected))
524 + }
525 + }()
526 + }
527 +
528 + tapi, err := api.WithOptions(testCase.apiOpts...)
529 + if err != nil {
530 + t.Fatal(err)
531 + }
532 +
533 + // Add!
534 +
535 + p, err := tapi.Unixfs().Add(ctx, data, opts...)
536 + close(eventOut)
537 + evtWg.Wait()
538 + if testCase.err != "" {
539 + if err == nil {
540 + t.Fatalf("expected an error: %s", testCase.err)
541 + }
542 + if err.Error() != testCase.err {
543 + t.Fatalf("expected an error: '%s' != '%s'", err.Error(), testCase.err)
544 + }
545 + return
546 + }
547 + if err != nil {
548 + t.Fatal(err)
549 + }
550 +
551 + if p.String() != testCase.path {
552 + t.Errorf("expected path %s, got: %s", testCase.path, p)
553 + }
554 +
555 + // compare file structure with Unixfs().Get
556 +
557 + var cmpFile func(origName string, orig files.Node, gotName string, got files.Node)
558 + cmpFile = func(origName string, orig files.Node, gotName string, got files.Node) {
559 + _, origDir := orig.(files.Directory)
560 + _, gotDir := got.(files.Directory)
561 +
562 + if origDir != gotDir {
563 + t.Fatal("file type mismatch")
564 + }
565 +
566 + if origName != gotName {
567 + t.Errorf("file name mismatch, orig='%s', got='%s'", origName, gotName)
568 + }
569 +
570 + if !gotDir {
571 + defer orig.Close()
572 + defer got.Close()
573 +
574 + do, err := ioutil.ReadAll(orig.(files.File))
575 + if err != nil {
576 + t.Fatal(err)
577 + }
578 +
579 + dg, err := ioutil.ReadAll(got.(files.File))
580 + if err != nil {
581 + t.Fatal(err)
582 + }
583 +
584 + if !bytes.Equal(do, dg) {
585 + t.Fatal("data not equal")
586 + }
587 +
588 + return
589 + }
590 +
591 + origIt := orig.(files.Directory).Entries()
592 + gotIt := got.(files.Directory).Entries()
593 +
594 + for {
595 + if origIt.Next() {
596 + if !gotIt.Next() {
597 + t.Fatal("gotIt out of entries before origIt")
598 + }
599 + } else {
600 + if gotIt.Next() {
601 + t.Fatal("origIt out of entries before gotIt")
602 + }
603 + break
604 + }
605 +
606 + cmpFile(origIt.Name(), origIt.Node(), gotIt.Name(), gotIt.Node())
607 + }
608 + if origIt.Err() != nil {
609 + t.Fatal(origIt.Err())
610 + }
611 + if gotIt.Err() != nil {
612 + t.Fatal(gotIt.Err())
613 + }
614 + }
615 +
616 + f, err := tapi.Unixfs().Get(ctx, p)
617 + if err != nil {
618 + t.Fatal(err)
619 + }
620 +
621 + orig := testCase.data()
622 + if testCase.expect != nil {
623 + orig = testCase.expect(orig)
624 + }
625 +
626 + cmpFile("", orig, "", f)
627 + })
628 + }
629 +}
630 +
631 +func TestAddPinned(t *testing.T) {
632 + ctx := context.Background()
633 + api, err := makeAPI(ctx)
634 + if err != nil {
635 + t.Error(err)
636 + }
637 +
638 + _, err = api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.Pin(true))
639 + if err != nil {
640 + t.Error(err)
641 + }
642 +
643 + pins, err := api.Pin().Ls(ctx)
644 + if len(pins) != 1 {
645 + t.Fatalf("expected 1 pin, got %d", len(pins))
646 + }
647 +
648 + if pins[0].Path().String() != "/ipld/QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk" {
649 + t.Fatalf("got unexpected pin: %s", pins[0].Path().String())
650 + }
651 +}
652 +
653 +func TestAddHashOnly(t *testing.T) {
654 + ctx := context.Background()
655 + api, err := makeAPI(ctx)
656 + if err != nil {
657 + t.Error(err)
658 + }
659 +
660 + p, err := api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.HashOnly(true))
661 + if err != nil {
662 + t.Error(err)
663 + }
664 +
665 + if p.String() != hello {
666 + t.Errorf("unxepected path: %s", p.String())
667 + }
668 +
669 + _, err = api.Block().Get(ctx, p)
670 + if err == nil {
671 + t.Fatal("expected an error")
672 + }
673 + if err.Error() != "blockservice: key not found" {
674 + t.Errorf("unxepected error: %s", err.Error())
675 + }
676 +}
677 +
678 +func TestGetEmptyFile(t *testing.T) {
679 + ctx := context.Background()
680 + api, err := makeAPI(ctx)
681 + if err != nil {
682 + t.Fatal(err)
683 + }
684 +
685 + _, err = api.Unixfs().Add(ctx, files.NewBytesFile([]byte{}))
686 + if err != nil {
687 + t.Fatal(err)
688 + }
689 +
690 + emptyFilePath, err := coreiface.ParsePath(emptyFile)
691 + if err != nil {
692 + t.Fatal(err)
693 + }
694 +
695 + r, err := api.Unixfs().Get(ctx, emptyFilePath)
696 + if err != nil {
697 + t.Fatal(err)
698 + }
699 +
700 + buf := make([]byte, 1) // non-zero so that Read() actually tries to read
701 + n, err := io.ReadFull(r.(files.File), buf)
702 + if err != nil && err != io.EOF {
703 + t.Error(err)
704 + }
705 + if !bytes.HasPrefix(buf, []byte{0x00}) {
706 + t.Fatalf("expected empty data, got [%s] [read=%d]", buf, n)
707 + }
708 +}
709 +
710 +func TestGetDir(t *testing.T) {
711 + ctx := context.Background()
712 + api, err := makeAPI(ctx)
713 + if err != nil {
714 + t.Error(err)
715 + }
716 + edir := unixfs.EmptyDirNode()
717 + _, err = api.Dag().Put(ctx, bytes.NewReader(edir.RawData()), options.Dag.Codec(cid.DagProtobuf), options.Dag.InputEnc("raw"))
718 + if err != nil {
719 + t.Error(err)
720 + }
721 + p := coreiface.IpfsPath(edir.Cid())
722 +
723 + emptyDir, err := api.Object().New(ctx, options.Object.Type("unixfs-dir"))
724 + if err != nil {
725 + t.Error(err)
726 + }
727 +
728 + if p.String() != coreiface.IpfsPath(emptyDir.Cid()).String() {
729 + t.Fatalf("expected path %s, got: %s", emptyDir.Cid(), p.String())
730 + }
731 +
732 + r, err := api.Unixfs().Get(ctx, coreiface.IpfsPath(emptyDir.Cid()))
733 + if err != nil {
734 + t.Error(err)
735 + }
736 +
737 + if _, ok := r.(files.Directory); !ok {
738 + t.Fatalf("expected a directory")
739 + }
740 +}
741 +
742 +func TestGetNonUnixfs(t *testing.T) {
743 + ctx := context.Background()
744 + api, err := makeAPI(ctx)
745 + if err != nil {
746 + t.Error(err)
747 + }
748 +
749 + nd := new(mdag.ProtoNode)
750 + _, err = api.Dag().Put(ctx, bytes.NewReader(nd.RawData()), options.Dag.Codec(nd.CidBuilder().GetCodec()), options.Dag.InputEnc("raw"))
751 + if err != nil {
752 + t.Error(err)
753 + }
754 +
755 + _, err = api.Unixfs().Get(ctx, coreiface.IpfsPath(nd.Cid()))
756 + if !strings.Contains(err.Error(), "proto: required field") {
757 + t.Fatalf("expected protobuf error, got: %s", err)
758 + }
759 +}
760 +
761 +func TestLs(t *testing.T) {
762 + ctx := context.Background()
763 + api, err := makeAPI(ctx)
764 + if err != nil {
765 + t.Error(err)
766 + }
767 +
768 + r := strings.NewReader("content-of-file")
769 + p, err := api.Unixfs().Add(ctx, files.NewMapDirectory(map[string]files.Node{
770 + "0": files.NewMapDirectory(map[string]files.Node{
771 + "name-of-file": files.NewReaderFile(r),
772 + }),
773 + }))
774 + if err != nil {
775 + t.Error(err)
776 + }
777 +
778 + links, err := api.Unixfs().Ls(ctx, p)
779 + if err != nil {
780 + t.Error(err)
781 + }
782 +
783 + if len(links) != 1 {
784 + t.Fatalf("expected 1 link, got %d", len(links))
785 + }
786 + if links[0].Size != 23 {
787 + t.Fatalf("expected size = 23, got %d", links[0].Size)
788 + }
789 + if links[0].Name != "name-of-file" {
790 + t.Fatalf("expected name = name-of-file, got %s", links[0].Name)
791 + }
792 + if links[0].Cid.String() != "QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr" {
793 + t.Fatalf("expected cid = QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr, got %s", links[0].Cid)
794 + }
795 +}
796 +
797 +func TestEntriesExpired(t *testing.T) {
798 + ctx := context.Background()
799 + api, err := makeAPI(ctx)
800 + if err != nil {
801 + t.Error(err)
802 + }
803 +
804 + r := strings.NewReader("content-of-file")
805 + p, err := api.Unixfs().Add(ctx, files.NewMapDirectory(map[string]files.Node{
806 + "0": files.NewMapDirectory(map[string]files.Node{
807 + "name-of-file": files.NewReaderFile(r),
808 + }),
809 + }))
810 + if err != nil {
811 + t.Error(err)
812 + }
813 +
814 + ctx, cancel := context.WithCancel(ctx)
815 +
816 + nd, err := api.Unixfs().Get(ctx, p)
817 + if err != nil {
818 + t.Error(err)
819 + }
820 + cancel()
821 +
822 + it := files.ToDir(nd).Entries()
823 + if it == nil {
824 + t.Fatal("it was nil")
825 + }
826 +
827 + if it.Next() {
828 + t.Fatal("Next succeeded")
829 + }
830 +
831 + if it.Err() != context.Canceled {
832 + t.Fatalf("unexpected error %s", it.Err())
833 + }
834 +
835 + if it.Next() {
836 + t.Fatal("Next succeeded")
837 + }
838 +}
839 +
840 +func TestLsEmptyDir(t *testing.T) {
841 + ctx := context.Background()
842 + api, err := makeAPI(ctx)
843 + if err != nil {
844 + t.Error(err)
845 + }
846 +
847 + _, err = api.Unixfs().Add(ctx, files.NewMapDirectory(map[string]files.Node{"0": files.NewSliceDirectory([]files.DirEntry{})}))
848 + if err != nil {
849 + t.Error(err)
850 + }
851 +
852 + emptyDir, err := api.Object().New(ctx, options.Object.Type("unixfs-dir"))
853 + if err != nil {
854 + t.Error(err)
855 + }
856 +
857 + links, err := api.Unixfs().Ls(ctx, coreiface.IpfsPath(emptyDir.Cid()))
858 + if err != nil {
859 + t.Error(err)
860 + }
861 +
862 + if len(links) != 0 {
863 + t.Fatalf("expected 0 links, got %d", len(links))
864 + }
865 +}
866 +
867 +// TODO(lgierth) this should test properly, with len(links) > 0
868 +func TestLsNonUnixfs(t *testing.T) {
869 + ctx := context.Background()
870 + api, err := makeAPI(ctx)
871 + if err != nil {
872 + t.Error(err)
873 + }
874 +
875 + nd, err := cbor.WrapObject(map[string]interface{}{"foo": "bar"}, math.MaxUint64, -1)
876 + if err != nil {
877 + t.Fatal(err)
878 + }
879 +
880 + _, err = api.Dag().Put(ctx, bytes.NewReader(nd.RawData()), options.Dag.Codec(cid.DagCBOR), options.Dag.InputEnc("raw"))
881 + if err != nil {
882 + t.Error(err)
883 + }
884 +
885 + links, err := api.Unixfs().Ls(ctx, coreiface.IpfsPath(nd.Cid()))
886 + if err != nil {
887 + t.Error(err)
888 + }
889 +
890 + if len(links) != 0 {
891 + t.Fatalf("expected 0 links, got %d", len(links))
892 + }
893 +}
894 +
895 +type closeTestF struct {
896 + files.File
897 + closed bool
898 +
899 + t *testing.T
900 +}
901 +
902 +type closeTestD struct {
903 + files.Directory
904 + closed bool
905 +
906 + t *testing.T
907 +}
908 +
909 +func (f *closeTestD) Close() error {
910 + if f.closed {
911 + f.t.Fatal("already closed")
912 + }
913 + f.closed = true
914 + return nil
915 +}
916 +
917 +func (f *closeTestF) Close() error {
918 + if f.closed {
919 + f.t.Fatal("already closed")
920 + }
921 + f.closed = true
922 + return nil
923 +}
924 +
925 +func TestAddCloses(t *testing.T) {
926 + ctx := context.Background()
927 + api, err := makeAPI(ctx)
928 + if err != nil {
929 + t.Error(err)
930 + }
931 +
932 + n4 := &closeTestF{files.NewBytesFile([]byte("foo")), false, t}
933 + d3 := &closeTestD{files.NewMapDirectory(map[string]files.Node{
934 + "sub": n4,
935 + }), false, t}
936 + n2 := &closeTestF{files.NewBytesFile([]byte("bar")), false, t}
937 + n1 := &closeTestF{files.NewBytesFile([]byte("baz")), false, t}
938 + d0 := &closeTestD{files.NewMapDirectory(map[string]files.Node{
939 + "a": d3,
940 + "b": n1,
941 + "c": n2,
942 + }), false, t}
943 +
944 + _, err = api.Unixfs().Add(ctx, d0)
945 + if err != nil {
946 + t.Error(err)
947 + }
948 +
949 + d0.Close() // Adder doesn't close top-level file
950 +
951 + for i, n := range []*closeTestF{n1, n2, n4} {
952 + if !n.closed {
953 + t.Errorf("file %d not closed!", i)
954 + }
955 + }
956 +
957 + for i, n := range []*closeTestD{d0, d3} {
958 + if !n.closed {
959 + t.Errorf("dir %d not closed!", i)
960 + }
961 + }
962 +
963 +}