mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-22 02:47:48 +08:00
This is intended as a replacement for sharness. These are vanilla Go tests which can be run in your IDE for quick iteration on end-to-end CLI tests. This also removes IPTB by duplicating its functionality in the test harness. This isn't a big deal...IPTB's complexity is mostly around the fact that its state needs to be saved to disk in between `iptb` command invocations, and that it uses Go plugins to inject functionality, neither of which are relevant here. If we merge this, we'll have to live with bifurcated tests for a while until they are all migrated. I'd recommend we self-enforce a rule that, if we need to touch a sharness test, we migrate it and one more test over to Go tests first. Then eventually we will have migrated everything.
239 lines
7.3 KiB
Go
239 lines
7.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/blang/semver/v4"
|
|
"github.com/ipfs/kubo/test/cli/harness"
|
|
. "github.com/ipfs/kubo/test/cli/testutils"
|
|
"github.com/stretchr/testify/assert"
|
|
gomod "golang.org/x/mod/module"
|
|
)
|
|
|
|
var versionRegexp = regexp.MustCompile(`^ipfs version (.+)$`)
|
|
|
|
func parseVersionOutput(s string) semver.Version {
|
|
versString := versionRegexp.FindStringSubmatch(s)[1]
|
|
v, err := semver.Parse(versString)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func TestCurDirIsWritable(t *testing.T) {
|
|
t.Parallel()
|
|
h := harness.NewT(t)
|
|
h.WriteFile("test.txt", "It works!")
|
|
}
|
|
|
|
func TestIPFSVersionCommandMatchesFlag(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
commandVersionStr := node.IPFS("version").Stdout.String()
|
|
commandVersionStr = strings.TrimSpace(commandVersionStr)
|
|
commandVersion := parseVersionOutput(commandVersionStr)
|
|
|
|
flagVersionStr := node.IPFS("--version").Stdout.String()
|
|
flagVersionStr = strings.TrimSpace(flagVersionStr)
|
|
flagVersion := parseVersionOutput(flagVersionStr)
|
|
|
|
assert.Equal(t, commandVersion, flagVersion)
|
|
}
|
|
|
|
func TestIPFSVersionAll(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
res := node.IPFS("version", "--all").Stdout.String()
|
|
res = strings.TrimSpace(res)
|
|
assert.Contains(t, res, "Kubo version")
|
|
assert.Contains(t, res, "Repo version")
|
|
assert.Contains(t, res, "System version")
|
|
assert.Contains(t, res, "Golang version")
|
|
}
|
|
|
|
func TestIPFSVersionDeps(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
res := node.IPFS("version", "deps").Stdout.String()
|
|
res = strings.TrimSpace(res)
|
|
lines := SplitLines(res)
|
|
|
|
assert.Equal(t, "github.com/ipfs/kubo@(devel)", lines[0])
|
|
|
|
for _, depLine := range lines[1:] {
|
|
split := strings.Split(depLine, " => ")
|
|
for _, moduleVersion := range split {
|
|
splitModVers := strings.Split(moduleVersion, "@")
|
|
modPath := splitModVers[0]
|
|
modVers := splitModVers[1]
|
|
assert.NoError(t, gomod.Check(modPath, modVers), "path: %s, version: %s", modPath, modVers)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIPFSCommands(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
cmds := node.IPFSCommands()
|
|
assert.Contains(t, cmds, "ipfs add")
|
|
assert.Contains(t, cmds, "ipfs daemon")
|
|
assert.Contains(t, cmds, "ipfs update")
|
|
}
|
|
|
|
func TestAllSubcommandsAcceptHelp(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
for _, cmd := range node.IPFSCommands() {
|
|
t.Run(fmt.Sprintf("command %q accepts help", cmd), func(t *testing.T) {
|
|
t.Parallel()
|
|
splitCmd := strings.Split(cmd, " ")[1:]
|
|
node.IPFS(StrCat("help", splitCmd)...)
|
|
node.IPFS(StrCat(splitCmd, "--help")...)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAllRootCommandsAreMentionedInHelpText(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
cmds := node.IPFSCommands()
|
|
var rootCmds []string
|
|
for _, cmd := range cmds {
|
|
splitCmd := strings.Split(cmd, " ")
|
|
if len(splitCmd) == 2 {
|
|
rootCmds = append(rootCmds, splitCmd[1])
|
|
}
|
|
}
|
|
|
|
// a few base commands are not expected to be in the help message
|
|
// but we default to requiring them to be in the help message, so that we
|
|
// have to make an conscious decision to exclude them
|
|
notInHelp := map[string]bool{
|
|
"object": true,
|
|
"shutdown": true,
|
|
"tar": true,
|
|
"urlstore": true,
|
|
"dns": true,
|
|
}
|
|
|
|
helpMsg := strings.TrimSpace(node.IPFS("--help").Stdout.String())
|
|
for _, rootCmd := range rootCmds {
|
|
if _, ok := notInHelp[rootCmd]; ok {
|
|
continue
|
|
}
|
|
assert.Contains(t, helpMsg, fmt.Sprintf(" %s", rootCmd))
|
|
}
|
|
}
|
|
|
|
func TestCommandDocsWidth(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
|
|
// require new commands to explicitly opt in to longer lines
|
|
allowList := map[string]bool{
|
|
"ipfs add": true,
|
|
"ipfs block put": true,
|
|
"ipfs daemon": true,
|
|
"ipfs config profile": true,
|
|
"ipfs pin remote service": true,
|
|
"ipfs name pubsub": true,
|
|
"ipfs object patch": true,
|
|
"ipfs swarm connect": true,
|
|
"ipfs p2p forward": true,
|
|
"ipfs p2p close": true,
|
|
"ipfs swarm disconnect": true,
|
|
"ipfs swarm addrs listen": true,
|
|
"ipfs dag resolve": true,
|
|
"ipfs dag get": true,
|
|
"ipfs object stat": true,
|
|
"ipfs pin remote add": true,
|
|
"ipfs config show": true,
|
|
"ipfs config edit": true,
|
|
"ipfs pin remote rm": true,
|
|
"ipfs pin remote ls": true,
|
|
"ipfs pin verify": true,
|
|
"ipfs dht get": true,
|
|
"ipfs pin remote service add": true,
|
|
"ipfs file ls": true,
|
|
"ipfs pin update": true,
|
|
"ipfs pin rm": true,
|
|
"ipfs p2p": true,
|
|
"ipfs resolve": true,
|
|
"ipfs dag stat": true,
|
|
"ipfs name publish": true,
|
|
"ipfs object diff": true,
|
|
"ipfs object patch add-link": true,
|
|
"ipfs name": true,
|
|
"ipfs object patch append-data": true,
|
|
"ipfs object patch set-data": true,
|
|
"ipfs dht put": true,
|
|
"ipfs diag profile": true,
|
|
"ipfs diag cmds": true,
|
|
"ipfs swarm addrs local": true,
|
|
"ipfs files ls": true,
|
|
"ipfs stats bw": true,
|
|
"ipfs urlstore add": true,
|
|
"ipfs swarm peers": true,
|
|
"ipfs pubsub sub": true,
|
|
"ipfs repo fsck": true,
|
|
"ipfs files write": true,
|
|
"ipfs swarm limit": true,
|
|
"ipfs commands completion fish": true,
|
|
"ipfs key export": true,
|
|
"ipfs routing get": true,
|
|
"ipfs refs": true,
|
|
"ipfs refs local": true,
|
|
"ipfs cid base32": true,
|
|
"ipfs pubsub pub": true,
|
|
"ipfs repo ls": true,
|
|
"ipfs routing put": true,
|
|
"ipfs key import": true,
|
|
"ipfs swarm peering add": true,
|
|
"ipfs swarm peering rm": true,
|
|
"ipfs swarm peering ls": true,
|
|
"ipfs update": true,
|
|
"ipfs swarm stats": true,
|
|
}
|
|
for _, cmd := range node.IPFSCommands() {
|
|
if _, ok := allowList[cmd]; ok {
|
|
continue
|
|
}
|
|
t.Run(fmt.Sprintf("command %q conforms to docs width limit", cmd), func(t *testing.T) {
|
|
splitCmd := strings.Split(cmd, " ")
|
|
resStr := node.IPFS(StrCat(splitCmd[1:], "--help")...)
|
|
res := strings.TrimSpace(resStr.Stdout.String())
|
|
for _, line := range SplitLines(res) {
|
|
assert.LessOrEqualf(t, len(line), 80, "expected width %d < 80 for %q", len(line), cmd)
|
|
}
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAllCommandsFailWhenPassedBadFlag(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
|
|
for _, cmd := range node.IPFSCommands() {
|
|
t.Run(fmt.Sprintf("command %q fails when passed a bad flag", cmd), func(t *testing.T) {
|
|
splitCmd := strings.Split(cmd, " ")
|
|
res := node.RunIPFS(StrCat(splitCmd, "--badflag")...)
|
|
assert.Equal(t, 1, res.Cmd.ProcessState.ExitCode())
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestCommandsFlags(t *testing.T) {
|
|
t.Parallel()
|
|
node := harness.NewT(t).NewNode()
|
|
resStr := node.IPFS("commands", "--flags").Stdout.String()
|
|
assert.Contains(t, resStr, "ipfs pin add --recursive / ipfs pin add -r")
|
|
assert.Contains(t, resStr, "ipfs id --format / ipfs id -f")
|
|
assert.Contains(t, resStr, "ipfs repo gc --quiet / ipfs repo gc -q")
|
|
}
|