github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/internal/runner/args.go (about)

     1  // Copyright 2018 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  package runner
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"go.chromium.org/tast/core/internal/command"
    16  	"go.chromium.org/tast/core/internal/protocol"
    17  
    18  	frameworkprotocol "go.chromium.org/tast/core/framework/protocol"
    19  )
    20  
    21  // RunnerType describes the type of test runner that is using this package.
    22  type RunnerType int // NOLINT
    23  
    24  const (
    25  	// LocalRunner indicates that this package is being used by local_test_runner.
    26  	LocalRunner RunnerType = iota
    27  	// RemoteRunner indicates that this package is being used by remote_test_runner.
    28  	RemoteRunner
    29  )
    30  
    31  // StaticConfig contains fixed parameters for the runner that are passed in from
    32  // local_test_runner or remote_test_runner.
    33  type StaticConfig struct {
    34  	// Type describes the type of runner being executed.
    35  	Type RunnerType
    36  
    37  	// KillStaleRunners dictates whether SIGTERM should be sent to any existing test runner processes
    38  	// when using RunnerRunTestsMode. This can help prevent confusing failures if multiple test jobs are
    39  	// incorrectly scheduled on the same DUT: https://crbug.com/941829
    40  	KillStaleRunners bool
    41  	// EnableSyslog specifies whether to copy logs to syslog. It should be
    42  	// always enabled on production, but can be disabled in unit tests to
    43  	// avoid spamming syslog.
    44  	EnableSyslog bool
    45  
    46  	// GetDUTInfo is a function to respond to GetDUTInfo RPC.
    47  	// If it is nil, an empty GetDUTInfoResponse is always returned.
    48  	GetDUTInfo func(ctx context.Context, req *protocol.GetDUTInfoRequest) (*protocol.GetDUTInfoResponse, error)
    49  
    50  	// GetSysInfoState is a function to respond to GetSysInfoState RPC.
    51  	// If it is nil, an empty GetSysInfoStateResponse is always returned.
    52  	GetSysInfoState func(ctx context.Context, req *protocol.GetSysInfoStateRequest) (*protocol.GetSysInfoStateResponse, error)
    53  
    54  	// CollectSysInfo is a function to respond to CollectSysInfo RPC.
    55  	// If it is nil, an empty CollectSysInfoResponse is always returned.
    56  	CollectSysInfo func(ctx context.Context, req *protocol.CollectSysInfoRequest) (*protocol.CollectSysInfoResponse, error)
    57  
    58  	// PrivateBundlesStampPath contains the path to a stamp file indicating private test bundles have been
    59  	// successfully downloaded and installed before. This prevents downloading private test bundles for
    60  	// every runner invocation.
    61  	PrivateBundlesStampPath string
    62  
    63  	// DeprecatedDirectRunDefaults is default configuration values used when
    64  	// the user executes a test runner directly to run tests.
    65  	//
    66  	// DEPRECATED: Direct test execution is deprecated. Tast tests should be
    67  	// always initiated with Tast CLI, in which case default values here are
    68  	// ignored.
    69  	DeprecatedDirectRunDefaults DeprecatedDirectRunConfig
    70  }
    71  
    72  // mode denotes the execution mode of the test runner.
    73  type mode int
    74  
    75  const (
    76  	// modeRPC is the standard execution mode of the test runner to start
    77  	// a gRPC server on stdin/stdout.
    78  	modeRPC mode = iota
    79  
    80  	// modeDeprecatedDirectRun is the deprecated execution mode of the test
    81  	// runner to allow users to run local tests directly on the DUT without
    82  	// Tast CLI.
    83  	modeDeprecatedDirectRun
    84  )
    85  
    86  // parsedArgs holds the results of command line parsing.
    87  type parsedArgs struct {
    88  	Mode mode
    89  
    90  	// DeprecatedDirectRunConfig contains configuration values used when
    91  	// the user executes a test runner directly to run tests.
    92  	//
    93  	// DEPRECATED: Direct test execution is deprecated. Tast tests should be
    94  	// always initiated with Tast CLI.
    95  	DeprecatedDirectRunConfig DeprecatedDirectRunConfig
    96  }
    97  
    98  // DeprecatedDirectRunConfig contains configuration values used when the user
    99  // executes a test runner directly to run tests.
   100  //
   101  // DEPRECATED: Direct test execution is deprecated. Tast tests should be always
   102  // initiated with Tast CLI.
   103  type DeprecatedDirectRunConfig struct {
   104  	// BundleGlob is a glob-style path matching test bundles to execute.
   105  	BundleGlob string
   106  	// DataDir is the path to the directory containing test data files.
   107  	DataDir string
   108  	// TempDir is the path to the directory under which temporary files for
   109  	// tests are written.
   110  	TempDir string
   111  
   112  	// Patterns contains patterns (either empty to run all tests, exactly one attribute expression,
   113  	// or one or more globs) describing which tests to run.
   114  	Patterns []string
   115  	// OutDir is the path to the base directory under which tests should write output files.
   116  	OutDir string
   117  	// Devservers contains URLs of devservers that can be used to download files.
   118  	Devservers []string
   119  	// WaitUntilReady indicates that the test bundle's "ready" function (see ReadyFunc) should
   120  	// be executed before any tests are executed.
   121  	WaitUntilReady bool
   122  	// ConnectionSpec is the DUT connection spec as [<user>@]host[:<port>].
   123  	// It is only relevant for remote tests.
   124  	ConnectionSpec string
   125  	// KeyFile is the path to the SSH private key to use to connect to the DUT.
   126  	// It is only relevant for remote tests.
   127  	KeyFile string
   128  	// KeyDir is the directory containing SSH private keys (typically $HOME/.ssh).
   129  	// It is only relevant for remote tests.
   130  	KeyDir string
   131  	// CheckDeps indicates whether test runners should skip tests whose
   132  	// dependencies are not satisfied by available features.
   133  	CheckDeps bool
   134  	// AvailableSoftwareFeatures contains a list of software features supported by the DUT.
   135  	AvailableSoftwareFeatures []string
   136  	// UnavailableSoftwareFeatures contains a list of software features supported by the DUT.
   137  	UnavailableSoftwareFeatures []string
   138  }
   139  
   140  // RunConfig generates protocol.RunConfig.
   141  // Tests should be a resolved list of test names according to a.Patterns.
   142  // Todo: Use primary dut for now, will add companion features in the future
   143  func (c *DeprecatedDirectRunConfig) RunConfig(tests []string) *protocol.RunConfig {
   144  	return &protocol.RunConfig{
   145  		Tests: tests,
   146  		Dirs: &protocol.RunDirectories{
   147  			DataDir: c.DataDir,
   148  			OutDir:  c.OutDir,
   149  			TempDir: c.TempDir,
   150  		},
   151  		Features: &protocol.Features{
   152  			CheckDeps: c.CheckDeps,
   153  			Dut: &frameworkprotocol.DUTFeatures{
   154  				Software: &frameworkprotocol.SoftwareFeatures{
   155  					Available:   c.AvailableSoftwareFeatures,
   156  					Unavailable: c.UnavailableSoftwareFeatures,
   157  				},
   158  			},
   159  		},
   160  		ServiceConfig: &protocol.ServiceConfig{
   161  			Devservers: c.Devservers,
   162  		},
   163  		DataFileConfig: &protocol.DataFileConfig{},
   164  		WaitUntilReady: c.WaitUntilReady,
   165  	}
   166  }
   167  
   168  // parseArgs parses runtime arguments.
   169  // clArgs contains command-line arguments and is typically os.Args[1:].
   170  func parseArgs(clArgs []string, stderr io.Writer, scfg *StaticConfig) (*parsedArgs, error) {
   171  	args := &parsedArgs{
   172  		Mode:                      modeDeprecatedDirectRun,
   173  		DeprecatedDirectRunConfig: scfg.DeprecatedDirectRunDefaults,
   174  	}
   175  
   176  	// Expose a limited amount of configurability via command-line flags to support running test runners manually.
   177  	var extraUSEFlags []string
   178  	flags := flag.NewFlagSet("", flag.ContinueOnError)
   179  	flags.SetOutput(stderr)
   180  	const usage = `Usage: %s [flag]... [pattern]...
   181  
   182  Run Tast tests matched by zero or more patterns.
   183  
   184  This executes test bundles to run Tast tests and is typically executed by the
   185  "tast" command. It can be executed manually to e.g. perform stress testing.
   186  
   187  Exits with 0 if all tests passed and with a non-zero exit code for all other
   188  errors, including the failure of an individual test.
   189  
   190  `
   191  	flags.Usage = func() {
   192  		fmt.Fprintf(stderr, usage, filepath.Base(os.Args[0]))
   193  		flags.PrintDefaults()
   194  	}
   195  	rpc := flags.Bool("rpc", false, "run gRPC server")
   196  	flags.StringVar(&args.DeprecatedDirectRunConfig.BundleGlob, "bundles",
   197  		args.DeprecatedDirectRunConfig.BundleGlob, "glob matching test bundles")
   198  	flags.StringVar(&args.DeprecatedDirectRunConfig.DataDir, "datadir",
   199  		args.DeprecatedDirectRunConfig.DataDir, "directory containing data files")
   200  	flags.StringVar(&args.DeprecatedDirectRunConfig.OutDir, "outdir",
   201  		args.DeprecatedDirectRunConfig.OutDir, "base directory to write output files to")
   202  	flags.Var(command.NewListFlag(",", func(v []string) { args.DeprecatedDirectRunConfig.Devservers = v }, nil),
   203  		"devservers", "comma-separated list of devserver URLs")
   204  	flags.Var(command.NewListFlag(",", func(v []string) { extraUSEFlags = v }, nil),
   205  		"extrauseflags", "comma-separated list of additional USE flags to inject when checking test dependencies")
   206  	flags.BoolVar(&args.DeprecatedDirectRunConfig.WaitUntilReady, "waituntilready",
   207  		true, "wait until DUT is ready before running tests")
   208  
   209  	if scfg.Type == RemoteRunner {
   210  		flags.StringVar(&args.DeprecatedDirectRunConfig.ConnectionSpec, "target",
   211  			"", "DUT connection spec as \"[<user>@]host[:<port>]\"")
   212  		flags.StringVar(&args.DeprecatedDirectRunConfig.KeyFile, "keyfile",
   213  			"", "path to SSH private key to use for connecting to DUT")
   214  		flags.StringVar(&args.DeprecatedDirectRunConfig.KeyDir, "keydir",
   215  			"", "directory containing SSH private keys (typically $HOME/.ssh)")
   216  	}
   217  
   218  	if err := flags.Parse(clArgs); err != nil {
   219  		return nil, command.NewStatusErrorf(statusBadArgs, "%v", err)
   220  	}
   221  
   222  	if *rpc {
   223  		args.Mode = modeRPC
   224  		return args, nil
   225  	}
   226  
   227  	args.DeprecatedDirectRunConfig.Patterns = flags.Args()
   228  
   229  	// When the runner is executed by the "tast run" command, the list of software features (used to skip
   230  	// unsupported tests) is passed in after having been gathered by an earlier call to local_test_runner
   231  	// with RunnerGetDUTInfoMode. When the runner is executed directly, gather the list here instead.
   232  	if scfg.GetDUTInfo != nil {
   233  		req := &protocol.GetDUTInfoRequest{ExtraUseFlags: extraUSEFlags}
   234  		res, err := scfg.GetDUTInfo(context.Background(), req)
   235  		if err != nil {
   236  			return nil, err
   237  		}
   238  
   239  		fs := res.GetDutInfo().GetFeatures().GetSoftware()
   240  		args.DeprecatedDirectRunConfig.CheckDeps = true
   241  		args.DeprecatedDirectRunConfig.AvailableSoftwareFeatures = fs.GetAvailable()
   242  		args.DeprecatedDirectRunConfig.UnavailableSoftwareFeatures = fs.GetUnavailable()
   243  		// Historically we set software features only. Do not bother to
   244  		// improve hardware feature support in direct mode.
   245  	}
   246  	return args, nil
   247  }