-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add basic CLI tests using Go Test
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.
- Loading branch information
Showing
22 changed files
with
1,657 additions
and
609 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
linters: | ||
enable: | ||
- stylecheck | ||
|
||
linters-settings: | ||
stylecheck: | ||
dot-import-whitelist: | ||
- github.com/ipfs/kubo/test/cli/testutils |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
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") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/ipfs/kubo/test/cli/harness" | ||
. "github.com/ipfs/kubo/test/cli/testutils" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestBashCompletion(t *testing.T) { | ||
t.Parallel() | ||
h := harness.NewT(t) | ||
node := h.NewNode() | ||
|
||
res := node.IPFS("commands", "completion", "bash") | ||
|
||
length := len(res.Stdout.String()) | ||
if length < 100 { | ||
t.Fatalf("expected a long Bash completion file, but got one of length %d", length) | ||
} | ||
|
||
t.Run("completion file can be loaded in bash", func(t *testing.T) { | ||
RequiresLinux(t) | ||
|
||
completionFile := h.WriteToTemp(res.Stdout.String()) | ||
res = h.Sh(fmt.Sprintf("source %s && type -t _ipfs", completionFile)) | ||
assert.NoError(t, res.Err) | ||
}) | ||
} |
Oops, something went wrong.