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

     1  // Copyright 2020 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 testing
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"reflect"
    11  	"time"
    12  
    13  	"go.chromium.org/tast/core/internal/protocol"
    14  	"go.chromium.org/tast/core/testing/hwdep"
    15  )
    16  
    17  const (
    18  	// ExternalLinkSuffix is a file name suffix for external data link files.
    19  	// These are JSON files that can be unmarshaled into the externalLink struct.
    20  	ExternalLinkSuffix = ".external"
    21  
    22  	// ExternalErrorSuffix is a file name suffix for external data download error files.
    23  	// An error message is written to the file when we encounter an error downloading
    24  	// the corresponding external data file. This mechanism is used to pass errors from
    25  	// the test runner (which downloads the files) to the test bundle so the bundle
    26  	// can include them in the test's output.
    27  	ExternalErrorSuffix = ".external-error"
    28  
    29  	// ExternalURLSuffix is a file name suffix to store external data file's source url.
    30  	// It is used to perform staleness check for external files. If this file is present
    31  	// tast first refer this file to see if it has previously downloaded file from the
    32  	// url. If so then file is not downloaded again. This is useful in case when
    33  	// the artifact name in External data files does not change, however the
    34  	// buildartifactsurl cli flag changed, resulting in different source url.
    35  	ExternalURLSuffix = ".external-url"
    36  )
    37  
    38  // TestFunc is the code associated with a test.
    39  type TestFunc func(context.Context, *State)
    40  
    41  // Test describes a registration of one or more test instances.
    42  //
    43  // Test can be passed to testing.AddTest to actually register test instances
    44  // to the framework.
    45  //
    46  // In the most basic form where Params field is empty, Test describes exactly
    47  // one test instance. If Params is not empty, multiple test instances are
    48  // generated on registration by merging each testing.Param to the base Test.
    49  type Test struct {
    50  	// Func is the function to be executed to perform the test.
    51  	Func TestFunc
    52  
    53  	// Desc is a short one-line description of the test.
    54  	Desc string
    55  
    56  	// Contacts is a list of email addresses of persons and groups who are familiar with the test.
    57  	// At least one personal email address of an active committer should be specified so that we can
    58  	// file bugs or ask for code reviews.
    59  	Contacts []string
    60  
    61  	// Attr contains freeform text attributes describing the test.
    62  	// See https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/test_attributes.md
    63  	// for commonly-used attributes.
    64  	Attr []string
    65  
    66  	// PrivateAttr contains freeform text private attributes describing the test.
    67  	// This should not be used other than Tast and tests.
    68  	// Note: this info is not retrievable in test results.
    69  	PrivateAttr []string
    70  
    71  	// SearchFlags contains key-value pairs describing the test.
    72  	// This information will be available in the test results, and can be used
    73  	// for custom test results filtering or any other mapping.
    74  	SearchFlags []*protocol.StringPair
    75  
    76  	// Data contains paths of data files needed by the test, relative to a "data" subdirectory within the
    77  	// directory in which Func is located.
    78  	Data []string
    79  
    80  	// Vars contains the names of runtime variables used to pass out-of-band data to tests.
    81  	// Values are supplied using "tast run -var=name=value", and tests can access values via State.Var.
    82  	Vars []string
    83  
    84  	// VarDeps serves similar purpose as Vars but lists runtime variables that
    85  	// are required to run the test.
    86  	// Whether test fails or skipped when runtime variables in VarDeps is
    87  	// missing is controlled by the flag -maybemissingvars for the Tast CLI.
    88  	//
    89  	// Tests should access runtime variables in VarDeps via State.RequiredVar.
    90  	VarDeps []string
    91  
    92  	// SoftwareDeps lists software features that are required to run the test.
    93  	// If any dependencies are not satisfied by the DUT, the test will be skipped.
    94  	// See https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/test_dependencies.md
    95  	// for more information about dependencies.
    96  	SoftwareDeps []string
    97  
    98  	// HardwareDeps describes hardware features and setup that are required to run the test.
    99  	HardwareDeps hwdep.Deps
   100  
   101  	// Pre contains a precondition that must be met before the test is run.
   102  	Pre Precondition
   103  
   104  	// Fixture is the name of the fixture the test depends on.
   105  	Fixture string
   106  
   107  	// Timeout contains the maximum duration for which Func may run before the test is aborted.
   108  	// This should almost always be set. If not specified, a reasonable default will be used,
   109  	// but tests should not depend on it.
   110  	// This field is serialized as an integer nanosecond count.
   111  	Timeout time.Duration
   112  
   113  	// Params lists the Param structs for parameterized tests.
   114  	Params []Param
   115  
   116  	// ServiceDeps contains a list of RPC service names in local test bundles that this remote test
   117  	// will access. This field is valid only for remote tests.
   118  	ServiceDeps []string
   119  
   120  	// LacrosStatus indicates whether lacros variants have been considered for this test or not.
   121  	LacrosStatus LacrosMetadata
   122  
   123  	// SoftwareDepsForAll lists software features of all DUTs that
   124  	// are required to run the test.
   125  	// It is a map of companion roles and software features.
   126  	// The role for primary DUT should be "".
   127  	// The primary DUT software dependency will be the union of
   128  	// SoftwareDeps and SoftwareDepsForAll[""].
   129  	// If any dependencies are not satisfied, the test will be skipped.
   130  	SoftwareDepsForAll map[string][]string
   131  
   132  	// HardwareDepsForAll describes hardware features and setup of all
   133  	// DUTs that are required to run the test.
   134  	// It is a map of companion roles and hardware features.
   135  	// The role for primary DUT should be "".
   136  	// The primary DUT hardware dependency will be the union of
   137  	// HardwareDeps and HardwareDepsForAll[""].
   138  	// If any dependencies are not satisfied, the test will be skipped.
   139  	HardwareDepsForAll map[string]hwdep.Deps
   140  
   141  	// Fields after this line are used  for automation purposes only, tests should not use
   142  	// these fields.
   143  
   144  	// TestBedDeps are used for defining test bed dependencies only, i.e., 'carrier:verizon'.
   145  	// These are not used by tests themselves, but added to test metadata definitions used by
   146  	// infra services.
   147  	TestBedDeps []string
   148  
   149  	// Requirements are used for linking test cases to requirements. These are not used by
   150  	// tests themselves, but added to test metadata definitions used by infra services.
   151  	Requirements []string
   152  
   153  	// Bug component id for filing bugs against this test, i.e. 'b:1234'. This field is not
   154  	// to be used by tests themselves, but added to test metadata definitions used by infra services.
   155  	BugComponent string
   156  }
   157  
   158  // LacrosMetadata indicates whether lacros variants have been considered for this test or not.
   159  type LacrosMetadata int
   160  
   161  const (
   162  	// LacrosVariantUnknown indicates that this test has not yet been checked as to whether it requires a lacros variant.
   163  	// New tests should not use this value, i.e. new tests should always consider lacros.
   164  	LacrosVariantUnknown = iota
   165  	// LacrosVariantNeeded indicates that a lacros variant for this is needed but hasn't been created yet.
   166  	LacrosVariantNeeded
   167  	// LacrosVariantExists indicates that all required lacros variants for this test have been created.
   168  	LacrosVariantExists
   169  	// LacrosVariantUnneeded indicates that lacros variants for this test are not needed.
   170  	LacrosVariantUnneeded
   171  )
   172  
   173  func (m LacrosMetadata) String() string {
   174  	switch m {
   175  	case LacrosVariantUnknown:
   176  		return "unknown"
   177  	case LacrosVariantNeeded:
   178  		return "needed"
   179  	case LacrosVariantExists:
   180  		return "exists"
   181  	case LacrosVariantUnneeded:
   182  		return "unneeded"
   183  	default:
   184  		return fmt.Sprintf("unexpected value (%d)", int(m))
   185  	}
   186  }
   187  
   188  // Param defines parameters for a parameterized test case.
   189  // See also https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Parameterized-tests
   190  type Param struct {
   191  	// Name is the name of this parameterized test.
   192  	// Full name of the test case will be category.TestFuncName.param_name,
   193  	// or category.TestFuncName if Name is empty.
   194  	// Name should match with [a-z0-9_]*.
   195  	Name string
   196  
   197  	// ExtraAttr contains freeform text attributes describing the test,
   198  	// in addition to Attr declared in the enclosing Test.
   199  	ExtraAttr []string
   200  
   201  	// ExtraPrivateAttr contains freeform text private attributes describing the test,
   202  	// in addition to PrivateAttr declared in the enclosing Test.
   203  	ExtraPrivateAttr []string
   204  
   205  	// ExtraSearchFlags contains name-value pairs describing the test,
   206  	// in addition to SearchFlags declared in the enclosing Test.
   207  	ExtraSearchFlags []*protocol.StringPair
   208  
   209  	// ExtraData contains paths of data files needed by the test case of this
   210  	// param in addition to Data declared in the enclosing Test.
   211  	ExtraData []string
   212  
   213  	// ExtraSoftwareDeps lists software features that are required to run the test case for this param,
   214  	// in addition to SoftwareDeps in the enclosing Test.
   215  	ExtraSoftwareDeps []string
   216  
   217  	// ExtraHardwareDeps describes hardware features and setup that are required to run the test for this
   218  	// param, in addition to HardwareDeps in the enclosing Test.
   219  	ExtraHardwareDeps hwdep.Deps
   220  
   221  	// ExtraRequirements are used for linking test cases to requirements. These are not used by
   222  	// tests themselves, but added to test metadata definitions used by infra services.  This slice is
   223  	// appended to an Requirements declared by the test.
   224  	ExtraRequirements []string
   225  
   226  	// Pre contains a precondition that must be met before the test is run.
   227  	// Can only be set if the enclosing test doesn't have one already set.
   228  	Pre Precondition
   229  
   230  	// Fixture is the name of the fixture the test depends on.
   231  	// Can only be set if the enclosing test doesn't have one already set.
   232  	Fixture string
   233  
   234  	// Timeout contains the maximum duration for which Func may run before the test is aborted.
   235  	// Can only be set if the enclosing test doesn't have one already set.
   236  	Timeout time.Duration
   237  
   238  	// Val is the value which can be retrieved from testing.State.Param() method.
   239  	Val interface{}
   240  
   241  	// ExtraSoftwareDepsForAll lists software features of all DUTs
   242  	// that are required to run the test case for this param,
   243  	// in addition to SoftwareDepsForAll in the enclosing Test.
   244  	// The primary DUT software dependency will be the union of
   245  	// SoftwareDeps, SoftwareDepsForAll[""], ExtraSoftwareDeps and
   246  	// ExtraSoftwareDepsForAll[""].
   247  	// It is a map of companion roles and software features.
   248  	ExtraSoftwareDepsForAll map[string][]string
   249  
   250  	// ExtraHardwareDepsForAll describes hardware features and setup
   251  	// companion DUTs that are required to run the test case for this param,
   252  	// in addition to HardwareDepsForAll in the enclosing Test.
   253  	// It is a map of companion roles and hardware features.
   254  	// The role for primary DUT should be ""
   255  	// The primary DUT hardware dependency will be the union of
   256  	// HardwareDeps, HardwareDepsForAll[""], ExtraHardwareDeps and
   257  	// ExtraHardwareDep and ExtraHardwareDepsForAll[""].
   258  	ExtraHardwareDepsForAll map[string]hwdep.Deps
   259  
   260  	// BugComponent overrides BugComponent defined in the test.
   261  	// This field is for infra/external use only and should not be used
   262  	// or referenced within the test code..
   263  	BugComponent string
   264  }
   265  
   266  // validate performs initial validations of Test.
   267  // Most validations are done while constructing TestInstance from a combination
   268  // of Test and Param in newTestInstance, not in this method, so that we can
   269  // validate fields of the final products. However some validations can be done
   270  // only in this method, e.g. checking consistencies among multiple parameters.
   271  func (t *Test) validate() error {
   272  	if err := validateParams(t.Params); err != nil {
   273  		return err
   274  	}
   275  	return nil
   276  }
   277  
   278  func validateParams(params []Param) error {
   279  	if len(params) == 0 {
   280  		return nil
   281  	}
   282  
   283  	// Ensure unique param name.
   284  	seen := make(map[string]struct{})
   285  	for _, p := range params {
   286  		name := p.Name
   287  		if _, ok := seen[name]; ok {
   288  			return fmt.Errorf("duplicate param name is found: %s", name)
   289  		}
   290  		seen[name] = struct{}{}
   291  	}
   292  
   293  	// Ensure all value assigned to Val should have the same type.
   294  	typ0 := reflect.TypeOf(params[0].Val)
   295  	for _, p := range params {
   296  		typ := reflect.TypeOf(p.Val)
   297  		if typ != typ0 {
   298  			return fmt.Errorf("unmatched Val type: got %v; want %v", typ, typ0)
   299  		}
   300  	}
   301  
   302  	return nil
   303  }