master
go 338 lines 10.7 KB
Raw
1 package cli
2
3 import (
4 "fmt"
5 "strings"
6 "testing"
7
8 "github.com/ipfs/go-cid"
9 "github.com/ipfs/go-test/random"
10 "github.com/ipfs/kubo/test/cli/harness"
11 . "github.com/ipfs/kubo/test/cli/testutils"
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14 )
15
16 type testPinsArgs struct {
17 runDaemon bool
18 pinArg string
19 lsArg string
20 baseArg string
21 }
22
23 func testPins(t *testing.T, args testPinsArgs) {
24 t.Run(fmt.Sprintf("test pins with args=%+v", args), func(t *testing.T) {
25 t.Parallel()
26 node := harness.NewT(t).NewNode().Init()
27 if args.runDaemon {
28 node.StartDaemon("--offline")
29 defer node.StopDaemon()
30 }
31
32 strs := []string{"a", "b", "c", "d", "e", "f", "g"}
33 dataToCid := map[string]string{}
34 cids := []string{}
35
36 ipfsAdd := func(t *testing.T, content string) string {
37 cidStr := node.IPFSAddStr(content, StrCat(args.baseArg, "--pin=false")...)
38
39 _, err := cid.Decode(cidStr)
40 require.NoError(t, err)
41 dataToCid[content] = cidStr
42 cids = append(cids, cidStr)
43 return cidStr
44 }
45
46 ipfsPinAdd := func(cids []string) []string {
47 input := strings.Join(cids, "\n")
48 return node.PipeStrToIPFS(input, StrCat("pin", "add", args.pinArg, args.baseArg)...).Stdout.Lines()
49 }
50
51 ipfsPinLS := func() string {
52 return node.IPFS(StrCat("pin", "ls", args.lsArg, args.baseArg)...).Stdout.Trimmed()
53 }
54
55 for _, s := range strs {
56 ipfsAdd(t, s)
57 }
58
59 // these subtests run sequentially since they depend on state
60
61 t.Run("check output of pin command", func(t *testing.T) {
62 resLines := ipfsPinAdd(cids)
63
64 for i, s := range resLines {
65 assert.Equal(t,
66 fmt.Sprintf("pinned %s recursively", cids[i]),
67 s,
68 )
69 }
70 })
71
72 t.Run("pin verify should succeed", func(t *testing.T) {
73 node.IPFS("pin", "verify")
74 })
75
76 t.Run("'pin verify --verbose' should include all the cids", func(t *testing.T) {
77 verboseVerifyOut := node.IPFS(StrCat("pin", "verify", "--verbose", args.baseArg)...).Stdout.String()
78 for _, cid := range cids {
79 assert.Contains(t, verboseVerifyOut, fmt.Sprintf("%s ok", cid))
80 }
81 })
82 t.Run("ls output should contain the cids", func(t *testing.T) {
83 lsOut := ipfsPinLS()
84 for _, cid := range cids {
85 assert.Contains(t, lsOut, cid)
86 }
87 })
88
89 t.Run("check 'pin ls hash' output", func(t *testing.T) {
90 lsHashOut := node.IPFS(StrCat("pin", "ls", args.lsArg, args.baseArg, dataToCid["b"])...)
91 lsHashOutStr := lsHashOut.Stdout.String()
92 assert.Equal(t, fmt.Sprintf("%s recursive\n", dataToCid["b"]), lsHashOutStr)
93 })
94
95 t.Run("unpinning works", func(t *testing.T) {
96 node.PipeStrToIPFS(strings.Join(cids, "\n"), "pin", "rm")
97 })
98
99 t.Run("test pin update", func(t *testing.T) {
100 cidA := dataToCid["a"]
101 cidB := dataToCid["b"]
102
103 ipfsPinAdd([]string{cidA})
104 beforeUpdate := ipfsPinLS()
105
106 assert.Contains(t, beforeUpdate, cidA)
107 assert.NotContains(t, beforeUpdate, cidB)
108
109 node.IPFS("pin", "update", "--unpin=true", cidA, cidB)
110 afterUpdate := ipfsPinLS()
111
112 assert.NotContains(t, afterUpdate, cidA)
113 assert.Contains(t, afterUpdate, cidB)
114
115 node.IPFS("pin", "update", "--unpin=true", cidB, cidB)
116 afterIdempotentUpdate := ipfsPinLS()
117
118 assert.Contains(t, afterIdempotentUpdate, cidB)
119
120 node.IPFS("pin", "rm", cidB)
121 })
122 })
123 }
124
125 func testPinsErrorReporting(t *testing.T, args testPinsArgs) {
126 t.Run(fmt.Sprintf("test pins error reporting with args=%+v", args), func(t *testing.T) {
127 t.Parallel()
128 node := harness.NewT(t).NewNode().Init()
129 if args.runDaemon {
130 node.StartDaemon("--offline")
131 defer node.StopDaemon()
132 }
133 randomCID := "Qme8uX5n9hn15pw9p6WcVKoziyyC9LXv4LEgvsmKMULjnV"
134 res := node.RunIPFS(StrCat("pin", "add", args.pinArg, randomCID)...)
135 assert.NotEqual(t, 0, res.ExitErr.ExitCode())
136 assert.Contains(t, res.Stderr.String(), "ipld: could not find")
137 })
138 }
139
140 func testPinDAG(t *testing.T, args testPinsArgs) {
141 t.Run(fmt.Sprintf("test pin DAG with args=%+v", args), func(t *testing.T) {
142 t.Parallel()
143 h := harness.NewT(t)
144 node := h.NewNode().Init()
145 if args.runDaemon {
146 node.StartDaemon("--offline")
147 defer node.StopDaemon()
148 }
149 bytes := random.Bytes(1 << 20) // 1 MiB
150 tmpFile := h.WriteToTemp(string(bytes))
151 cid := node.IPFS(StrCat("add", args.pinArg, "--pin=false", "-q", tmpFile)...).Stdout.Trimmed()
152
153 node.IPFS("pin", "add", "--recursive=true", cid)
154 node.IPFS("pin", "rm", cid)
155
156 // remove part of the DAG
157 part := node.IPFS("refs", cid).Stdout.Lines()[0]
158 node.IPFS("block", "rm", part)
159
160 res := node.RunIPFS("pin", "add", "--recursive=true", cid)
161 assert.NotEqual(t, 0, res)
162 assert.Contains(t, res.Stderr.String(), "ipld: could not find")
163 })
164 }
165
166 func testPinProgress(t *testing.T, args testPinsArgs) {
167 t.Run(fmt.Sprintf("test pin progress with args=%+v", args), func(t *testing.T) {
168 t.Parallel()
169 h := harness.NewT(t)
170 node := h.NewNode().Init()
171
172 if args.runDaemon {
173 node.StartDaemon("--offline")
174 defer node.StopDaemon()
175 }
176
177 bytes := random.Bytes(1 << 20) // 1 MiB
178 tmpFile := h.WriteToTemp(string(bytes))
179 cid := node.IPFS(StrCat("add", args.pinArg, "--pin=false", "-q", tmpFile)...).Stdout.Trimmed()
180
181 res := node.RunIPFS("pin", "add", "--progress", cid)
182 node.Runner.AssertNoError(res)
183
184 assert.Contains(t, res.Stderr.String(), " 5 nodes (1.0 MB)")
185 })
186 }
187
188 func TestPins(t *testing.T) {
189 t.Parallel()
190 t.Run("test pinning without daemon running", func(t *testing.T) {
191 t.Parallel()
192 testPinsErrorReporting(t, testPinsArgs{})
193 testPinsErrorReporting(t, testPinsArgs{pinArg: "--progress"})
194 testPinDAG(t, testPinsArgs{})
195 testPinDAG(t, testPinsArgs{pinArg: "--raw-leaves"})
196 testPinProgress(t, testPinsArgs{})
197 testPins(t, testPinsArgs{})
198 testPins(t, testPinsArgs{pinArg: "--progress"})
199 testPins(t, testPinsArgs{pinArg: "--progress", lsArg: "--stream"})
200 testPins(t, testPinsArgs{baseArg: "--cid-base=base32"})
201 testPins(t, testPinsArgs{lsArg: "--stream", baseArg: "--cid-base=base32"})
202 })
203
204 t.Run("test pinning with daemon running without network", func(t *testing.T) {
205 t.Parallel()
206 testPinsErrorReporting(t, testPinsArgs{runDaemon: true})
207 testPinsErrorReporting(t, testPinsArgs{runDaemon: true, pinArg: "--progress"})
208 testPinDAG(t, testPinsArgs{runDaemon: true})
209 testPinDAG(t, testPinsArgs{runDaemon: true, pinArg: "--raw-leaves"})
210 testPinProgress(t, testPinsArgs{runDaemon: true})
211 testPins(t, testPinsArgs{runDaemon: true})
212 testPins(t, testPinsArgs{runDaemon: true, pinArg: "--progress"})
213 testPins(t, testPinsArgs{runDaemon: true, pinArg: "--progress", lsArg: "--stream"})
214 testPins(t, testPinsArgs{runDaemon: true, baseArg: "--cid-base=base32"})
215 testPins(t, testPinsArgs{runDaemon: true, lsArg: "--stream", baseArg: "--cid-base=base32"})
216 })
217
218 pinLs := func(node *harness.Node, args ...string) []string {
219 return strings.Split(node.IPFS(StrCat("pin", "ls", args)...).Stdout.Trimmed(), "\n")
220 }
221
222 t.Run("test pinning with names cli text output", func(t *testing.T) {
223 t.Parallel()
224
225 node := harness.NewT(t).NewNode().Init()
226 cidAStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
227 cidBStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
228
229 _ = node.IPFS("pin", "add", "--name", "testPin", cidAStr)
230
231 outARegular := cidAStr + " recursive"
232 outADetailed := outARegular + " testPin"
233 outBRegular := cidBStr + " recursive"
234 outBDetailed := outBRegular + " testPin"
235
236 lsOut := pinLs(node, "-t=recursive")
237 require.Contains(t, lsOut, outARegular)
238 require.NotContains(t, lsOut, outADetailed)
239
240 lsOut = pinLs(node, "-t=recursive", "--names")
241 require.Contains(t, lsOut, outADetailed)
242 require.NotContains(t, lsOut, outARegular)
243
244 _ = node.IPFS("pin", "update", cidAStr, cidBStr)
245 lsOut = pinLs(node, "-t=recursive", "--names")
246 require.Contains(t, lsOut, outBDetailed)
247 require.NotContains(t, lsOut, outADetailed)
248 })
249
250 t.Run("test listing pins with names that contain specific string", func(t *testing.T) {
251 t.Parallel()
252
253 node := harness.NewT(t).NewNode().Init()
254 cidAStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
255 cidBStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
256 cidCStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
257
258 outA := cidAStr + " recursive testPin"
259 outB := cidBStr + " recursive testPin"
260 outC := cidCStr + " recursive randPin"
261
262 // make sure both -n and --name work
263 for _, nameParam := range []string{"--name", "-n"} {
264 _ = node.IPFS("pin", "add", "--name", "testPin", cidAStr)
265 lsOut := pinLs(node, "-t=recursive", nameParam+"=test")
266 require.Contains(t, lsOut, outA)
267 lsOut = pinLs(node, "-t=recursive", nameParam+"=randomLabel")
268 require.NotContains(t, lsOut, outA)
269
270 _ = node.IPFS("pin", "add", "--name", "testPin", cidBStr)
271 lsOut = pinLs(node, "-t=recursive", nameParam+"=test")
272 require.Contains(t, lsOut, outA)
273 require.Contains(t, lsOut, outB)
274
275 _ = node.IPFS("pin", "add", "--name", "randPin", cidCStr)
276 lsOut = pinLs(node, "-t=recursive", nameParam+"=rand")
277 require.NotContains(t, lsOut, outA)
278 require.NotContains(t, lsOut, outB)
279 require.Contains(t, lsOut, outC)
280
281 lsOut = pinLs(node, "-t=recursive", nameParam+"=testPin")
282 require.Contains(t, lsOut, outA)
283 require.Contains(t, lsOut, outB)
284 require.NotContains(t, lsOut, outC)
285 }
286 })
287
288 t.Run("test overwriting pin with name", func(t *testing.T) {
289 t.Parallel()
290
291 node := harness.NewT(t).NewNode().Init()
292 cidStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
293
294 outBefore := cidStr + " recursive A"
295 outAfter := cidStr + " recursive B"
296
297 _ = node.IPFS("pin", "add", "--name", "A", cidStr)
298 lsOut := pinLs(node, "-t=recursive", "--names")
299 require.Contains(t, lsOut, outBefore)
300 require.NotContains(t, lsOut, outAfter)
301
302 _ = node.IPFS("pin", "add", "--name", "B", cidStr)
303 lsOut = pinLs(node, "-t=recursive", "--names")
304 require.Contains(t, lsOut, outAfter)
305 require.NotContains(t, lsOut, outBefore)
306 })
307
308 // JSON that is also the wire format of /api/v0
309 t.Run("test pinning with names json output", func(t *testing.T) {
310 t.Parallel()
311
312 node := harness.NewT(t).NewNode().Init()
313 cidAStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
314 cidBStr := node.IPFSAddStr(string(random.Bytes(1000)), "--pin=false")
315
316 _ = node.IPFS("pin", "add", "--name", "testPinJson", cidAStr)
317
318 outARegular := `"` + cidAStr + `":{"Type":"recursive"`
319 outADetailed := outARegular + `,"Name":"testPinJson"`
320 outBRegular := `"` + cidBStr + `":{"Type":"recursive"`
321 outBDetailed := outBRegular + `,"Name":"testPinJson"`
322
323 pinLs := func(args ...string) string {
324 return node.IPFS(StrCat("pin", "ls", "--enc=json", args)...).Stdout.Trimmed()
325 }
326
327 lsOut := pinLs("-t=recursive")
328 require.Contains(t, lsOut, outARegular)
329 require.NotContains(t, lsOut, outADetailed)
330
331 lsOut = pinLs("-t=recursive", "--names")
332 require.Contains(t, lsOut, outADetailed)
333
334 _ = node.IPFS("pin", "update", cidAStr, cidBStr)
335 lsOut = pinLs("-t=recursive", "--names")
336 require.Contains(t, lsOut, outBDetailed)
337 })
338 }