master
go 181 lines 5.66 KB
Raw
1 package harness
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "os"
8 "reflect"
9 "strings"
10
11 . "github.com/ipfs/kubo/test/cli/testutils"
12 )
13
14 func (n *Node) IPFSCommands() []string {
15 res := n.IPFS("commands").Stdout.String()
16 res = strings.TrimSpace(res)
17 split := SplitLines(res)
18 var cmds []string
19 for _, line := range split {
20 trimmed := strings.TrimSpace(line)
21 if trimmed == "ipfs" {
22 continue
23 }
24 cmds = append(cmds, trimmed)
25 }
26 return cmds
27 }
28
29 func (n *Node) SetIPFSConfig(key string, val any, flags ...string) {
30 valBytes, err := json.Marshal(val)
31 if err != nil {
32 log.Panicf("marshling config for key '%s': %s", key, err)
33 }
34 valStr := string(valBytes)
35
36 args := []string{"config", "--json"}
37 args = append(args, flags...)
38 args = append(args, key, valStr)
39 n.IPFS(args...)
40
41 // validate the config was set correctly
42
43 // Create a new value which is a pointer to the same type as the source.
44 var newVal any
45 if val != nil {
46 // If it is not nil grab the type with reflect.
47 newVal = reflect.New(reflect.TypeOf(val)).Interface()
48 } else {
49 // else just set a pointer to an any.
50 var anything any
51 newVal = &anything
52 }
53 n.GetIPFSConfig(key, newVal)
54 // dereference newVal using reflect to load the resulting value
55 if !reflect.DeepEqual(val, reflect.ValueOf(newVal).Elem().Interface()) {
56 log.Panicf("key '%s' did not retain value '%s' after it was set, got '%s'", key, val, newVal)
57 }
58 }
59
60 func (n *Node) GetIPFSConfig(key string, val any) {
61 res := n.IPFS("config", key)
62 valStr := strings.TrimSpace(res.Stdout.String())
63 // only when the result is a string is the result not well-formed JSON,
64 // so check the value type and add quotes if it's expected to be a string
65 reflectVal := reflect.ValueOf(val)
66 if reflectVal.Kind() == reflect.Pointer && reflectVal.Elem().Kind() == reflect.String {
67 valStr = fmt.Sprintf(`"%s"`, valStr)
68 }
69 err := json.Unmarshal([]byte(valStr), val)
70 if err != nil {
71 log.Fatalf("unmarshaling config for key '%s', value '%s': %s", key, valStr, err)
72 }
73 }
74
75 func (n *Node) IPFSAddStr(content string, args ...string) string {
76 log.Debugf("node %d adding content '%s' with args: %v", n.ID, PreviewStr(content), args)
77 return n.IPFSAdd(strings.NewReader(content), args...)
78 }
79
80 // IPFSAddDeterministic produces a CID of a file of a certain size, filled with deterministically generated bytes based on some seed.
81 // Size is specified as a humanize string (e.g., "256KiB", "1MiB").
82 // This ensures deterministic CID on the other end, that can be used in tests.
83 func (n *Node) IPFSAddDeterministic(size string, seed string, args ...string) string {
84 log.Debugf("node %d adding %s of deterministic pseudo-random data with seed %q and args: %v", n.ID, size, seed, args)
85 reader, err := DeterministicRandomReader(size, seed)
86 if err != nil {
87 panic(err)
88 }
89 return n.IPFSAdd(reader, args...)
90 }
91
92 // IPFSAddDeterministicBytes produces a CID of a file of exactly `size` bytes, filled with deterministically generated bytes based on some seed.
93 // Use this when exact byte precision is needed (e.g., threshold tests at T and T+1 bytes).
94 func (n *Node) IPFSAddDeterministicBytes(size int64, seed string, args ...string) string {
95 log.Debugf("node %d adding %d bytes of deterministic pseudo-random data with seed %q and args: %v", n.ID, size, seed, args)
96 reader, err := DeterministicRandomReaderBytes(size, seed)
97 if err != nil {
98 panic(err)
99 }
100 return n.IPFSAdd(reader, args...)
101 }
102
103 func (n *Node) IPFSAdd(content io.Reader, args ...string) string {
104 log.Debugf("node %d adding with args: %v", n.ID, args)
105 fullArgs := []string{"add", "-q"}
106 fullArgs = append(fullArgs, args...)
107 res := n.Runner.MustRun(RunRequest{
108 Path: n.IPFSBin,
109 Args: fullArgs,
110 CmdOpts: []CmdOpt{RunWithStdin(content)},
111 })
112 out := strings.TrimSpace(res.Stdout.String())
113 log.Debugf("add result: %q", out)
114 return out
115 }
116
117 func (n *Node) IPFSBlockPut(content io.Reader, args ...string) string {
118 log.Debugf("node %d block put with args: %v", n.ID, args)
119 fullArgs := []string{"block", "put"}
120 fullArgs = append(fullArgs, args...)
121 res := n.Runner.MustRun(RunRequest{
122 Path: n.IPFSBin,
123 Args: fullArgs,
124 CmdOpts: []CmdOpt{RunWithStdin(content)},
125 })
126 out := strings.TrimSpace(res.Stdout.String())
127 log.Debugf("block put result: %q", out)
128 return out
129 }
130
131 func (n *Node) IPFSDAGPut(content io.Reader, args ...string) string {
132 log.Debugf("node %d dag put with args: %v", n.ID, args)
133 fullArgs := []string{"dag", "put"}
134 fullArgs = append(fullArgs, args...)
135 res := n.Runner.MustRun(RunRequest{
136 Path: n.IPFSBin,
137 Args: fullArgs,
138 CmdOpts: []CmdOpt{RunWithStdin(content)},
139 })
140 out := strings.TrimSpace(res.Stdout.String())
141 log.Debugf("dag put result: %q", out)
142 return out
143 }
144
145 func (n *Node) IPFSDagImport(content io.Reader, cid string, args ...string) error {
146 log.Debugf("node %d dag import with args: %v", n.ID, args)
147 fullArgs := []string{"dag", "import", "--pin-roots=false"}
148 fullArgs = append(fullArgs, args...)
149 res := n.Runner.MustRun(RunRequest{
150 Path: n.IPFSBin,
151 Args: fullArgs,
152 CmdOpts: []CmdOpt{RunWithStdin(content)},
153 })
154 if res.Err != nil {
155 return res.Err
156 }
157 res = n.Runner.MustRun(RunRequest{
158 Path: n.IPFSBin,
159 Args: []string{"block", "stat", "--offline", cid},
160 })
161 return res.Err
162 }
163
164 // IPFSDagExport exports a DAG rooted at cid to a CAR file at carPath.
165 func (n *Node) IPFSDagExport(cid string, carPath string, args ...string) error {
166 log.Debugf("node %d dag export of %s to %q with args: %v", n.ID, cid, carPath, args)
167 car, err := os.Create(carPath)
168 if err != nil {
169 return err
170 }
171 defer car.Close()
172
173 fullArgs := append([]string{"dag", "export"}, args...)
174 fullArgs = append(fullArgs, cid)
175 res := n.Runner.MustRun(RunRequest{
176 Path: n.IPFSBin,
177 Args: fullArgs,
178 CmdOpts: []CmdOpt{RunWithStdout(car)},
179 })
180 return res.Err
181 }