mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 18:37:45 +08:00
* chore: apply go fix modernizers from Go 1.26
automated refactoring: interface{} to any, slices.Contains,
and other idiomatic updates.
* feat(ci): add `go fix` check to Go analysis workflow
ensures Go 1.26 modernizers are applied, fails CI if `go fix ./...`
produces any changes (similar to existing `go fmt` enforcement)
180 lines
5.6 KiB
Go
180 lines
5.6 KiB
Go
package harness
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
|
|
. "github.com/ipfs/kubo/test/cli/testutils"
|
|
)
|
|
|
|
func (n *Node) IPFSCommands() []string {
|
|
res := n.IPFS("commands").Stdout.String()
|
|
res = strings.TrimSpace(res)
|
|
split := SplitLines(res)
|
|
var cmds []string
|
|
for _, line := range split {
|
|
trimmed := strings.TrimSpace(line)
|
|
if trimmed == "ipfs" {
|
|
continue
|
|
}
|
|
cmds = append(cmds, trimmed)
|
|
}
|
|
return cmds
|
|
}
|
|
|
|
func (n *Node) SetIPFSConfig(key string, val any, flags ...string) {
|
|
valBytes, err := json.Marshal(val)
|
|
if err != nil {
|
|
log.Panicf("marshling config for key '%s': %s", key, err)
|
|
}
|
|
valStr := string(valBytes)
|
|
|
|
args := []string{"config", "--json"}
|
|
args = append(args, flags...)
|
|
args = append(args, key, valStr)
|
|
n.IPFS(args...)
|
|
|
|
// validate the config was set correctly
|
|
|
|
// Create a new value which is a pointer to the same type as the source.
|
|
var newVal any
|
|
if val != nil {
|
|
// If it is not nil grab the type with reflect.
|
|
newVal = reflect.New(reflect.TypeOf(val)).Interface()
|
|
} else {
|
|
// else just set a pointer to an any.
|
|
var anything any
|
|
newVal = &anything
|
|
}
|
|
n.GetIPFSConfig(key, newVal)
|
|
// dereference newVal using reflect to load the resulting value
|
|
if !reflect.DeepEqual(val, reflect.ValueOf(newVal).Elem().Interface()) {
|
|
log.Panicf("key '%s' did not retain value '%s' after it was set, got '%s'", key, val, newVal)
|
|
}
|
|
}
|
|
|
|
func (n *Node) GetIPFSConfig(key string, val any) {
|
|
res := n.IPFS("config", key)
|
|
valStr := strings.TrimSpace(res.Stdout.String())
|
|
// only when the result is a string is the result not well-formed JSON,
|
|
// so check the value type and add quotes if it's expected to be a string
|
|
reflectVal := reflect.ValueOf(val)
|
|
if reflectVal.Kind() == reflect.Pointer && reflectVal.Elem().Kind() == reflect.String {
|
|
valStr = fmt.Sprintf(`"%s"`, valStr)
|
|
}
|
|
err := json.Unmarshal([]byte(valStr), val)
|
|
if err != nil {
|
|
log.Fatalf("unmarshaling config for key '%s', value '%s': %s", key, valStr, err)
|
|
}
|
|
}
|
|
|
|
func (n *Node) IPFSAddStr(content string, args ...string) string {
|
|
log.Debugf("node %d adding content '%s' with args: %v", n.ID, PreviewStr(content), args)
|
|
return n.IPFSAdd(strings.NewReader(content), args...)
|
|
}
|
|
|
|
// IPFSAddDeterministic produces a CID of a file of a certain size, filled with deterministically generated bytes based on some seed.
|
|
// Size is specified as a humanize string (e.g., "256KiB", "1MiB").
|
|
// This ensures deterministic CID on the other end, that can be used in tests.
|
|
func (n *Node) IPFSAddDeterministic(size string, seed string, args ...string) string {
|
|
log.Debugf("node %d adding %s of deterministic pseudo-random data with seed %q and args: %v", n.ID, size, seed, args)
|
|
reader, err := DeterministicRandomReader(size, seed)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return n.IPFSAdd(reader, args...)
|
|
}
|
|
|
|
// IPFSAddDeterministicBytes produces a CID of a file of exactly `size` bytes, filled with deterministically generated bytes based on some seed.
|
|
// Use this when exact byte precision is needed (e.g., threshold tests at T and T+1 bytes).
|
|
func (n *Node) IPFSAddDeterministicBytes(size int64, seed string, args ...string) string {
|
|
log.Debugf("node %d adding %d bytes of deterministic pseudo-random data with seed %q and args: %v", n.ID, size, seed, args)
|
|
reader, err := DeterministicRandomReaderBytes(size, seed)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return n.IPFSAdd(reader, args...)
|
|
}
|
|
|
|
func (n *Node) IPFSAdd(content io.Reader, args ...string) string {
|
|
log.Debugf("node %d adding with args: %v", n.ID, args)
|
|
fullArgs := []string{"add", "-q"}
|
|
fullArgs = append(fullArgs, args...)
|
|
res := n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: fullArgs,
|
|
CmdOpts: []CmdOpt{RunWithStdin(content)},
|
|
})
|
|
out := strings.TrimSpace(res.Stdout.String())
|
|
log.Debugf("add result: %q", out)
|
|
return out
|
|
}
|
|
|
|
func (n *Node) IPFSBlockPut(content io.Reader, args ...string) string {
|
|
log.Debugf("node %d block put with args: %v", n.ID, args)
|
|
fullArgs := []string{"block", "put"}
|
|
fullArgs = append(fullArgs, args...)
|
|
res := n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: fullArgs,
|
|
CmdOpts: []CmdOpt{RunWithStdin(content)},
|
|
})
|
|
out := strings.TrimSpace(res.Stdout.String())
|
|
log.Debugf("block put result: %q", out)
|
|
return out
|
|
}
|
|
|
|
func (n *Node) IPFSDAGPut(content io.Reader, args ...string) string {
|
|
log.Debugf("node %d dag put with args: %v", n.ID, args)
|
|
fullArgs := []string{"dag", "put"}
|
|
fullArgs = append(fullArgs, args...)
|
|
res := n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: fullArgs,
|
|
CmdOpts: []CmdOpt{RunWithStdin(content)},
|
|
})
|
|
out := strings.TrimSpace(res.Stdout.String())
|
|
log.Debugf("dag put result: %q", out)
|
|
return out
|
|
}
|
|
|
|
func (n *Node) IPFSDagImport(content io.Reader, cid string, args ...string) error {
|
|
log.Debugf("node %d dag import with args: %v", n.ID, args)
|
|
fullArgs := []string{"dag", "import", "--pin-roots=false"}
|
|
fullArgs = append(fullArgs, args...)
|
|
res := n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: fullArgs,
|
|
CmdOpts: []CmdOpt{RunWithStdin(content)},
|
|
})
|
|
if res.Err != nil {
|
|
return res.Err
|
|
}
|
|
res = n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: []string{"block", "stat", "--offline", cid},
|
|
})
|
|
return res.Err
|
|
}
|
|
|
|
// IPFSDagExport exports a DAG rooted at cid to a CAR file at carPath.
|
|
func (n *Node) IPFSDagExport(cid string, carPath string) error {
|
|
log.Debugf("node %d dag export of %s to %q", n.ID, cid, carPath)
|
|
car, err := os.Create(carPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer car.Close()
|
|
|
|
res := n.Runner.MustRun(RunRequest{
|
|
Path: n.IPFSBin,
|
|
Args: []string{"dag", "export", cid},
|
|
CmdOpts: []CmdOpt{RunWithStdout(car)},
|
|
})
|
|
return res.Err
|
|
}
|