Skip to content

Commit

Permalink
test: better talosctl ls tests
Browse files Browse the repository at this point in the history
Refs #3018.

Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
  • Loading branch information
AlekSi authored and talos-bot committed May 20, 2021
1 parent 04ddda9 commit 4fe6912
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 47 deletions.
5 changes: 4 additions & 1 deletion hack/test/e2e-docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ function create_cluster {
}

function destroy_cluster() {
"${TALOSCTL}" cluster destroy --name "${CLUSTER_NAME}"
"${TALOSCTL}" cluster destroy --name "${CLUSTER_NAME}" --provisioner "${PROVISIONER}"
}

create_cluster
get_kubeconfig
${KUBECTL} config set-cluster e2e-docker --server https://10.5.0.2:6443
run_talos_integration_test_docker
run_kubernetes_integration_test

# Unlike other local e2e tests, we don't destroy the cluster there as it is used by CAPI and AWS/GCP e2e tests later.
# destroy_cluster
2 changes: 1 addition & 1 deletion hack/test/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ function build_registry_mirrors {
if [[ "${CI:-false}" == "true" ]]; then
REGISTRY_MIRROR_FLAGS=

for registry in docker.io ghcr.io k8s.gcr.io quay.io gcr.io registry.dev.talos-systems.io; do
for registry in docker.io k8s.gcr.io quay.io gcr.io ghcr.io registry.dev.talos-systems.io; do
local service="registry-${registry//./-}.ci.svc"
local addr=`python3 -c "import socket; print(socket.gethostbyname('${service}'))"`

Expand Down
2 changes: 1 addition & 1 deletion hack/test/provision-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ case "${CI:-false}" in
true)
mirror_flag=""

for registry in docker.io ghcr.io k8s.gcr.io quay.io gcr.io registry.dev.talos-systems.io; do
for registry in docker.io k8s.gcr.io quay.io gcr.io ghcr.io registry.dev.talos-systems.io; do
service="registry-${registry//./-}.ci.svc"
addr=`python3 -c "import socket; print(socket.gethostbyname('${service}'))"`

Expand Down
6 changes: 3 additions & 3 deletions internal/integration/base/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ func (cliSuite *CLISuite) buildCLICmd(args []string) *exec.Cmd {
}

// RunCLI runs talosctl binary with the options provided.
func (cliSuite *CLISuite) RunCLI(args []string, options ...RunOption) {
Run(&cliSuite.Suite, cliSuite.buildCLICmd(args), options...)
func (cliSuite *CLISuite) RunCLI(args []string, options ...RunOption) (stdout string) {
return Run(&cliSuite.Suite, cliSuite.buildCLICmd(args), options...)
}

// RunAndWaitForMatch retries command until output matches.
func (cliSuite *CLISuite) RunAndWaitForMatch(args []string, regex *regexp.Regexp, duration time.Duration, options ...retry.Option) {
cliSuite.Assert().NoError(retry.Constant(duration, options...).Retry(func() error {
stdout, _, err := RunAndWait(&cliSuite.Suite, cliSuite.buildCLICmd(args))
stdout, _, err := runAndWait(&cliSuite.Suite, cliSuite.buildCLICmd(args))
if err != nil {
return retry.UnexpectedError(err)
}
Expand Down
56 changes: 30 additions & 26 deletions internal/integration/base/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,6 @@ func ShouldFail() RunOption {
}
}

// ShouldSucceed tells Run command should succeed (that is default).
func ShouldSucceed() RunOption {
return func(opts *runOptions) {
opts.shouldFail = true
}
}

// StderrNotEmpty tells run that stderr of the command should not be empty.
func StderrNotEmpty() RunOption {
return func(opts *runOptions) {
Expand Down Expand Up @@ -107,10 +100,10 @@ func StderrMatchFunc(f MatchFunc) RunOption {
}
}

// RunAndWait launches the command and waits for completion.
// runAndWait launches the command and waits for completion.
//
// RunAndWait doesn't do any assertions on result.
func RunAndWait(suite *suite.Suite, cmd *exec.Cmd) (stdoutBuf, stderrBuf *bytes.Buffer, err error) {
// runAndWait doesn't do any assertions on result.
func runAndWait(suite *suite.Suite, cmd *exec.Cmd) (stdoutBuf, stderrBuf *bytes.Buffer, err error) {
var stdout, stderr bytes.Buffer

cmd.Stdin = nil
Expand Down Expand Up @@ -142,17 +135,26 @@ func RunAndWait(suite *suite.Suite, cmd *exec.Cmd) (stdoutBuf, stderrBuf *bytes.
return &stdout, &stderr, err
}

// Run executes command and asserts on its exit status/output.
// Run executes command, asserts on its exit status/output, and returns stdout.
//
//nolint:gocyclo
func Run(suite *suite.Suite, cmd *exec.Cmd, options ...RunOption) {
//nolint:gocyclo,nakedret
func Run(suite *suite.Suite, cmd *exec.Cmd, options ...RunOption) (stdout string) {
var opts runOptions

for _, o := range options {
o(&opts)
}

stdout, stderr, err := RunAndWait(suite, cmd)
stdoutBuf, stderrBuf, err := runAndWait(suite, cmd)

if stdoutBuf != nil {
stdout = stdoutBuf.String()
}

var stderr string
if stderrBuf != nil {
stderr = stderrBuf.String()
}

if err == nil {
if opts.shouldFail {
Expand All @@ -169,39 +171,41 @@ func Run(suite *suite.Suite, cmd *exec.Cmd, options ...RunOption) {
}
}

if opts.stderrNotEmpty {
suite.Assert().NotEmpty(stderr.String(), "stderr should be not empty")
if opts.stdoutEmpty {
suite.Assert().Empty(stdout, "stdout should be empty")
} else {
suite.Assert().Empty(stderr.String(), "stderr should be empty")
suite.Assert().NotEmpty(stdout, "stdout should be not empty")
}

if opts.stdoutEmpty {
suite.Assert().Empty(stdout.String(), "stdout should be empty")
if opts.stderrNotEmpty {
suite.Assert().NotEmpty(stderr, "stderr should be not empty")
} else {
suite.Assert().NotEmpty(stdout.String(), "stdout should be not empty")
suite.Assert().Empty(stderr, "stderr should be empty")
}

for _, rx := range opts.stdoutRegexps {
suite.Assert().Regexp(rx, stdout.String())
suite.Assert().Regexp(rx, stdout)
}

for _, rx := range opts.stderrRegexps {
suite.Assert().Regexp(rx, stderr.String())
suite.Assert().Regexp(rx, stderr)
}

for _, rx := range opts.stdoutNegativeRegexps {
suite.Assert().NotRegexp(rx, stdout.String())
suite.Assert().NotRegexp(rx, stdout)
}

for _, rx := range opts.stderrNegativeRegexps {
suite.Assert().NotRegexp(rx, stderr.String())
suite.Assert().NotRegexp(rx, stderr)
}

for _, f := range opts.stdoutMatchers {
suite.Assert().NoError(f(stdout.String()), "stdout match: %q", stdout.String())
suite.Assert().NoError(f(stdout), "stdout match: %q", stdout)
}

for _, f := range opts.stderrMatchers {
suite.Assert().NoError(f(stderr.String()), "stderr match: %q", stderr.String())
suite.Assert().NoError(f(stderr), "stderr match: %q", stderr)
}

return
}
83 changes: 83 additions & 0 deletions internal/integration/cli/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
package cli

import (
"fmt"
"os"
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/assert"

"github.com/talos-systems/talos/internal/integration/base"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
)

// ListSuite verifies dmesg command.
Expand All @@ -31,6 +38,82 @@ func (suite *ListSuite) TestSuccess() {
base.StdoutShouldNotMatch(regexp.MustCompile(`os-release`)))
}

// TestDepth tests various combinations of --recurse and --depth flags.
func (suite *ListSuite) TestDepth() {
suite.T().Parallel()

node := suite.RandomDiscoveredNode(machine.TypeControlPlane)

// checks that enough separators are encountered in the output
runAndCheck := func(t *testing.T, expectedSeparators int, flags ...string) {
args := append([]string{"list", "--nodes", node, "/system"}, flags...)
stdout := suite.RunCLI(args)

lines := strings.Split(strings.TrimSpace(stdout), "\n")
assert.Greater(t, len(lines), 2)
assert.Equal(t, []string{"NODE", "NAME"}, strings.Fields(lines[0]))
assert.Equal(t, []string{"."}, strings.Fields(lines[1])[1:])

var maxActualSeparators int

for _, line := range lines[2:] {
actualSeparators := strings.Count(strings.Fields(line)[1], string(os.PathSeparator))

msg := fmt.Sprintf(
"too many separators (actualSeparators = %d, expectedSeparators = %d)\nflags: %s\nlines:\n%s",
actualSeparators, expectedSeparators, strings.Join(flags, " "), strings.Join(lines, "\n"),
)
if !assert.LessOrEqual(t, actualSeparators, expectedSeparators, msg) {
return
}

if maxActualSeparators < actualSeparators {
maxActualSeparators = actualSeparators
}
}

msg := fmt.Sprintf(
"not enough separators (maxActualSeparators = %d, expectedSeparators = %d)\nflags: %s\nlines:\n%s",
maxActualSeparators, expectedSeparators, strings.Join(flags, " "), strings.Join(lines, "\n"),
)
assert.Equal(t, maxActualSeparators, expectedSeparators, msg)
}

for _, test := range []struct {
separators int
flags []string
}{
{separators: 0},

{separators: 0, flags: []string{"--recurse=false"}},
{separators: 5, flags: []string{"--recurse=true"}},

{separators: 0, flags: []string{"--depth=-1"}},
{separators: 0, flags: []string{"--depth=0"}},
{separators: 0, flags: []string{"--depth=1"}},
{separators: 0, flags: []string{"--depth=2"}},
{separators: 0, flags: []string{"--depth=3"}},

{separators: 0, flags: []string{"--recurse=false", "--depth=-1"}},
{separators: 0, flags: []string{"--recurse=false", "--depth=0"}},
{separators: 0, flags: []string{"--recurse=false", "--depth=1"}},
{separators: 0, flags: []string{"--recurse=false", "--depth=2"}},
{separators: 0, flags: []string{"--recurse=false", "--depth=3"}},

{separators: 5, flags: []string{"--recurse=true", "--depth=-1"}},
{separators: 5, flags: []string{"--recurse=true", "--depth=0"}},
{separators: 0, flags: []string{"--recurse=true", "--depth=1"}},
{separators: 1, flags: []string{"--recurse=true", "--depth=2"}},
{separators: 2, flags: []string{"--recurse=true", "--depth=3"}},
} {
test := test
suite.Run(strings.Join(test.flags, ","), func() {
suite.T().Parallel()
runAndCheck(suite.T(), test.separators, test.flags...)
})
}
}

func init() {
allSuites = append(allSuites, new(ListSuite))
}
59 changes: 46 additions & 13 deletions pkg/archiver/walker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package archiver_test

import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
Expand Down Expand Up @@ -67,20 +68,52 @@ func (suite *WalkerSuite) TestIterationFilter() {
}

func (suite *WalkerSuite) TestIterationMaxRecurseDepth() {
ch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithMaxRecurseDepth(1))
suite.Require().NoError(err)

relPaths := []string(nil)

for fi := range ch {
suite.Require().NoError(fi.Error)
relPaths = append(relPaths, fi.RelPath)
for _, test := range []struct {
maxDepth int
result []string
}{
{
maxDepth: -1,
result: []string{".", "dev", "dev/random", "etc", "etc/certs", "etc/certs/ca.crt", "etc/hostname", "lib", "lib/dynalib.so", "usr", "usr/bin", "usr/bin/cp", "usr/bin/mv"},
},
{
// confusing case
maxDepth: 0,
result: []string{".", "dev", "etc", "lib", "usr"},
},
{
maxDepth: 1,
result: []string{".", "dev", "etc", "lib", "usr"},
},
{
maxDepth: 2,
result: []string{".", "dev", "dev/random", "etc", "etc/certs", "etc/hostname", "lib", "lib/dynalib.so", "usr", "usr/bin"},
},
{
maxDepth: 3,
result: []string{".", "dev", "dev/random", "etc", "etc/certs", "etc/certs/ca.crt", "etc/hostname", "lib", "lib/dynalib.so", "usr", "usr/bin", "usr/bin/cp", "usr/bin/mv"},
},
{
maxDepth: 4,
result: []string{".", "dev", "dev/random", "etc", "etc/certs", "etc/certs/ca.crt", "etc/hostname", "lib", "lib/dynalib.so", "usr", "usr/bin", "usr/bin/cp", "usr/bin/mv"},
},
} {
test := test
suite.Run(fmt.Sprint(test.maxDepth), func() {
suite.T().Parallel()

ch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithMaxRecurseDepth(test.maxDepth))
suite.Require().NoError(err)

var result []string
for fi := range ch {
suite.Require().NoError(fi.Error)
result = append(result, fi.RelPath)
}

suite.Equal(test.result, result)
})
}

suite.Assert().Equal([]string{
".", "dev", "etc", "lib", "usr",
},
relPaths)
}

func (suite *WalkerSuite) TestIterationFile() {
Expand Down
2 changes: 1 addition & 1 deletion pkg/provision/providers/qemu/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func launchVM(config *LaunchConfig) error {
}
}

fmt.Fprintf(os.Stderr, "starting qemu with args:\n%s\n", strings.Join(args, " "))
fmt.Fprintf(os.Stderr, "starting %s with args:\n%s\n", config.QemuExecutable, strings.Join(args, " "))
cmd := exec.Command(
config.QemuExecutable,
args...,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The follow are requirements for creating the set of caching proxies:

## Launch the Caching Docker Registry Proxies

Talos pulls from `docker.io`, `k8s.gcr.io`, `gcr.io`, `ghcr.io` and `quay.io` by default.
Talos pulls from `docker.io`, `k8s.gcr.io`, `quay.io`, `gcr.io`, and `ghcr.io` by default.
If your configuration is different, you might need to modify the commands below:

```bash
Expand Down

0 comments on commit 4fe6912

Please sign in to comment.