| // Copyright 2017 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "bytes" |
| "context" |
| "encoding/json" |
| "flag" |
| "fmt" |
| "io" |
| "os" |
| |
| "github.com/google/subcommands" |
| |
| "go.chromium.org/tast/core/cmd/tast/internal/run/config" |
| "go.chromium.org/tast/core/internal/logging" |
| "go.chromium.org/tast/core/internal/run/resultsjson" |
| ) |
| |
| // listCmd implements subcommands.Command to support listing tests. |
| type listCmd struct { |
| json bool // marshal tests to JSON instead of just printing names |
| cfg *config.MutableConfig // shared config for listing tests |
| wrapper runWrapper // wraps calls to run package |
| stdout io.Writer // where to write tests |
| } |
| |
| var _ = subcommands.Command(&runCmd{}) |
| |
| // newListCmd returns a new listCmd that will write tests to stdout. |
| func newListCmd(stdout io.Writer, trunkDir string) *listCmd { |
| return &listCmd{ |
| cfg: config.NewMutableConfig(config.ListTestsMode, tastDir, trunkDir), |
| wrapper: &realRunWrapper{}, |
| stdout: stdout, |
| } |
| } |
| |
| func (*listCmd) Name() string { return "list" } |
| func (*listCmd) Synopsis() string { return "list tests" } |
| func (*listCmd) Usage() string { |
| return `Usage: list [flag]... <target> [pattern]... |
| |
| Description: |
| List tests matched by zero or more patterns. |
| |
| Target: |
| The target is an SSH connection spec of the form "[user@]host[:port]". |
| |
| Pattern: |
| Patterns are either globs matching test names or a single test attribute |
| boolean expression in parentheses. |
| |
| To list all the tests: |
| |
| $ tast list <target> |
| |
| To list tests based attributes pattern, mention single argument surrounded by parentheses. Example: |
| |
| $ tast list <target> '(("dep:chrome" || "dep:android") && !informational)' |
| |
| To list tests based on test name wildcard pattern, use *. Example: |
| |
| $ tast list <target> 'ui*' 'wilco*' |
| |
| Flag: |
| ` |
| } |
| |
| func (lc *listCmd) SetFlags(f *flag.FlagSet) { |
| // TODO(derat): Add -listtype: https://crbug.com/831849 |
| f.BoolVar(&lc.json, "json", false, "print full test details as JSON") |
| lc.cfg.SetFlags(f) |
| } |
| |
| func (lc *listCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { |
| if len(f.Args()) == 0 { |
| logging.Info(ctx, "Missing target.\n\n"+lc.Usage()) |
| return subcommands.ExitUsageError |
| } |
| if err := lc.cfg.DeriveDefaults(); err != nil { |
| logging.Info(ctx, "Failed to derive defaults: ", err) |
| return subcommands.ExitUsageError |
| } |
| lc.cfg.Target = f.Args()[0] |
| lc.cfg.Patterns = f.Args()[1:] |
| |
| var logInMemory bytes.Buffer |
| logger := logging.NewSinkLogger(logging.LevelDebug, true, logging.NewWriterSink(&logInMemory)) |
| ctx = logging.AttachLoggerNoPropagation(ctx, logger) |
| |
| state := config.DeprecatedState{} |
| results, err := lc.wrapper.run(ctx, lc.cfg.Freeze(), &state) |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "%v\nERROR: %v\n", logInMemory.String(), err) |
| return subcommands.ExitFailure |
| } |
| tests := make([]*resultsjson.Test, len(results)) |
| for i := range results { |
| tests[i] = &results[i].Test |
| } |
| |
| if err := lc.printTests(tests); err != nil { |
| logging.Info(ctx, "Failed to write tests: ", err) |
| return subcommands.ExitFailure |
| } |
| return subcommands.ExitSuccess |
| } |
| |
| // printTests writes the supplied tests to lc.stdout. |
| func (lc *listCmd) printTests(tests []*resultsjson.Test) error { |
| if lc.json { |
| enc := json.NewEncoder(lc.stdout) |
| enc.SetIndent("", " ") |
| return enc.Encode(tests) |
| } |
| |
| // If -json wasn't passed, just print test names, one per line. |
| for _, t := range tests { |
| if _, err := fmt.Fprintln(lc.stdout, t.Name); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |