github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/docs/writing_tests.md (about)

     1  # Tast: Writing Tests (go/tast-writing)
     2  
     3  [TOC]
     4  
     5  ## Adding tests
     6  
     7  ### Test names
     8  
     9  Tests are identified by names like `login.Chrome` or `platform.ConnectToDBus`.
    10  The portion before the period, called the _category_, is the final component of
    11  the test's package name, while the portion after the period is the name of the
    12  exported Go function that implements the test.
    13  
    14  Test function names should follow [Go's naming conventions], and [acronyms
    15  should be fully capitalized]. Test names should not end with `Test`, both
    16  because it's redundant and because the `_test.go` filename suffix is reserved in
    17  Go for unit tests.
    18  
    19  Test names are automatically derived from tests' package and function names and
    20  should not be explicitly specified when defining tests.
    21  
    22  [Go's naming conventions]: https://golang.org/doc/effective_go.html#names
    23  [acronyms should be fully capitalized]: https://github.com/golang/go/wiki/CodeReviewComments#initialisms
    24  
    25  ### Code location
    26  
    27  Public tests built into the default `cros` local and remote [test bundles] are
    28  checked into the [tast-tests repository] under the
    29  [src/go.chromium.org/tast-tests/cros/local/bundles/cros/] and
    30  [src/go.chromium.org/tast-tests/cros/remote/bundles/cros/] directories (which may also be
    31  accessed by the `local_tests` and `remote_tests` symlinks at the top of the
    32  repository). Private tests are checked into private repositories such as the
    33  [tast-tests-private repository], and built into non-`cros` test bundles.
    34  
    35  Tests are categorized into packages based on the functionality that
    36  they exercise; for example, the [ui package] contains local tests that exercise
    37  the ChromeOS UI. The category package needs to be directly under the bundle
    38  package. Thus the category package path should be matched with
    39  `go.chromium.org/tast/core/(local|remote)/bundles/(?P<bundlename>[^/]+)/(?P<category>[^/]+)`.
    40  
    41  A local test named `ui.DoSomething` should be defined in a file named
    42  `src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/do_something.go` (i.e. convert the
    43  test name to lowercase and insert underscores between words).
    44  
    45  Support packages used by multiple test categories located in
    46  [src/go.chromium.org/tast-tests/cros/local/] and [src/go.chromium.org/tast-tests/cros/remote/], alongside the
    47  `bundles/` directories. For example, the [chrome package] can be used by local
    48  tests to interact with Chrome.
    49  
    50  If there's a support package that's specific to a single category, it's often
    51  best to place it underneath the category's directory. See the [Scoping and
    52  shared code] section.
    53  
    54  Packages outside `go.chromium.org/tast-tests/cros/local/...` should not import packages in `go.chromium.org/tast-tests/cros/local/...`, and
    55  packages outside `go.chromium.org/tast-tests/cros/remote/...` should not import packages in `go.chromium.org/tast-tests/cros/remote/...`.
    56  If local and remote packages should share the same code, put them in `go.chromium.org/tast-tests/cros/common/...`.
    57  
    58  [test bundles]: overview.md#Test-bundles
    59  [tast-tests repository]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD
    60  [tast-tests-private repository]: https://chrome-internal.googlesource.com/chromeos/platform/tast-tests-private/+/HEAD
    61  [src/go.chromium.org/tast-tests/cros/local/bundles/cros/]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/bundles/cros/
    62  [src/go.chromium.org/tast-tests/cros/remote/bundles/cros/]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/remote/bundles/cros/
    63  [ui package]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/
    64  [src/go.chromium.org/tast-tests/cros/local/]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/
    65  [src/go.chromium.org/tast-tests/cros/remote/]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/remote/
    66  [chrome package]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/chrome/
    67  [Scoping and shared code]: #Scoping-and-shared-code
    68  
    69  ### Test registration
    70  
    71  A test needs to be registered by calling `testing.AddTest()` in the test entry
    72  file, which is located directly under a category package. The registration
    73  needs to be done in `init()` function in the file. The registration should be
    74  declarative, which means:
    75  - `testing.AddTest()` should be the only statement of `init()`'s body.
    76  - `testing.AddTest()` should take a pointer of a `testing.Test` composite literal.
    77  
    78  Each field of testing.Test should be constant-like. Fields should not be set
    79  using the invocation of custom functions (however, append() is allowed), or
    80  using variables. In particular, we say constant-like is any of these things:
    81  
    82  - An array literal of constant-like.
    83  - A go constant.
    84  - A literal value.
    85  - A var defined as an array literal of go constants or literal values (N.B. not
    86    general constant-likes).
    87  - A var forwarding (set to) another constant-like var.
    88  - A call to append on some constant-likes.
    89  - A call to hwdep.D, but please apply the spirit of constant-like to the
    90    arguments to hwdep.D.
    91  
    92  The test registration code will be similar to the following:
    93  
    94  ```go
    95  // Copyright 2018 The ChromiumOS Authors
    96  // Use of this source code is governed by a BSD-style license that can be
    97  // found in the LICENSE file.
    98  
    99  package ui
   100  
   101  import (
   102  	"context"
   103  
   104  	"go.chromium.org/tast/core/testing"
   105  )
   106  
   107  func init() {
   108  	testing.AddTest(&testing.Test{
   109  		Func:         DoSomething,
   110  		Desc:         "Does X to verify Y",
   111  		Contacts:     []string{"team@google.com", "me@chromium.org"},
   112  		BugComponent: "b:12345",
   113  		Attr:         []string{"group:mainline", "informational"},
   114  		SoftwareDeps: []string{"chrome"},
   115  		Timeout:      3 * time.Minute,
   116  	})
   117  }
   118  
   119  func DoSomething(ctx context.Context, s *testing.State) {
   120  	// The actual test goes here.
   121  }
   122  ```
   123  
   124  Tests have to specify the descriptions in `Desc`, which should be a string literal.
   125  
   126  Tests have to specify email addresses of persons and groups who are familiar
   127  with those tests in `Contacts`. The first element of the slice should be a group
   128  alias for the team ultimately responsible for the test. Subsequent elements
   129  should be individuals or groups who can be contacted for code reviews, bugs,
   130  and any issue with the test's usage. To help aid triage and on-call rotations,
   131  partner owned tests must specify a Google email contact that can be
   132  reached by on-call rotations. Any google.com or chromium.org groups listed should
   133  accept email posts from non-members within the organization. Users who no longer
   134  work on Chrome OS or with test's owning team should remove themselves as a
   135  contact.
   136  
   137  Tests have to specify a `BugComponent`, which should be a string with a prefix
   138  indicating the bug tracker. The string's contents point to the location where
   139  bugs regarding the test should initially be filed. A prefix is used to
   140  distinguish between different bug trackers. For Buganizer, use "b:" plus
   141  the componentid, e.g. "b:1034625". For Chromium bug tracker, use "crbug:" plus
   142  the component label, e.g. "crbug:Blink>JavaScript>WebAssembly".
   143  
   144  Tests have to specify [attributes] to describe how they are used in ChromeOS
   145  testing. A test belongs to zero or more groups by declaring attributes with
   146  `group:`-prefix. Typically functional tests belong to the mainline group by
   147  declaring the `group:mainline` attribute. New mainline tests should have the
   148  `informational` attribute, as tests without this attribute will block the Commit
   149  Queue on failure otherwise. The `Attr` fields should be an array literal of
   150  string literals.
   151  
   152  The `SoftwareDeps` field lists [software dependencies] that should be satisfied
   153  in order for the test to run. Its value should be an array literal of string
   154  literals or (possibly qualified) identifiers which are constant value.
   155  
   156  Tests should always set the `Timeout` field to specify the maximum duration for
   157  which Func may run before the test is aborted. If not specified, a reasonable
   158  default will be used, but tests should not depend on it.
   159  
   160  #### Disabling tests
   161  
   162  If a test has no `group:*` attribute assigned it will be effectively disabled,
   163  it will not be run by any automation.
   164  If a test needs to be disabled leave a comment in the test source with the
   165  reason. If applicable, create a bug explaining under what circumstances the
   166  test can be enabled.
   167  
   168  [Contacts]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#Test
   169  [attributes]: test_attributes.md
   170  [software dependencies]: test_dependencies.md
   171  
   172  ### Adding new test categories
   173  
   174  When adding a new test category, you must update the test bundle's `imports.go`
   175  file (either [local/bundles/cros/imports.go] or [remote/bundles/cros/imports.go]) to
   176  underscore-import the new package so its `init` functions will be executed to
   177  register tests.
   178  
   179  [local/bundles/cros/imports.go]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/bundles/cros/imports.go
   180  [remote/bundles/cros/imports.go]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/remote/bundles/cros/imports.go
   181  
   182  ## Coding style and best practices
   183  
   184  Test code should be formatted by [gofmt] and checked by [go vet], [golint] and
   185  [tast-lint]. These tools are configured to run as pre-upload hooks, so don't
   186  skip them.
   187  
   188  Tast code should also follow Go's established best practices as described by
   189  these documents:
   190  
   191  *   [Effective Go]
   192  *   [Go Code Review Comments]
   193  
   194  The [Go FAQ] may also be helpful. Additional resources are linked from the [Go
   195  Documentation] page.
   196  
   197  [gofmt]: https://golang.org/cmd/gofmt/
   198  [go vet]: https://golang.org/cmd/vet/
   199  [golint]: https://github.com/golang/lint
   200  [tast-lint]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/src/go.chromium.org/tast/core/cmd/tast-lint/
   201  [Effective Go]: https://golang.org/doc/effective_go.html
   202  [Go Code Review Comments]: https://github.com/golang/go/wiki/CodeReviewComments
   203  [Go FAQ]: https://golang.org/doc/faq
   204  [Go Documentation]: https://golang.org/doc/
   205  
   206  ### Documentation
   207  
   208  Packages and exported identifiers (e.g. types, functions, constants, variables)
   209  should be documented by [Godoc]-style comments. Godoc comments are optional for
   210  test functions, since the `Test.Desc` field already contains a brief description
   211  of the test.
   212  
   213  [Godoc]: https://blog.golang.org/godoc-documenting-go-code
   214  
   215  ### Unit tests
   216  
   217  Support packages should be exercised by unit tests when possible. Unit tests can
   218  cover edge cases that may not be typically seen when using the package, and they
   219  greatly aid in future refactorings (since it can be hard to determine the full
   220  set of Tast-based tests that must be run to exercise the package). See [How to
   221  Write Go Code: Testing] and [Go's testing package] for more information about
   222  writing unit tests for Go code. The [Best practices for writing ChromeOS unit
   223  tests] document contains additional suggestions that may be helpful (despite
   224  being C++-centric).
   225  
   226  Setting `FEATURES=test` when emerging a test bundle package
   227  (`tast-local-tests-cros` or `tast-remote-tests-cros`) will run all unit tests
   228  for the corresponding packages in the `tast-tests` repository (i.e.
   229  `go.chromium.org/tast-tests/cros/local/...` or `go.chromium.org/tast-tests/cros/remote/...`, respectively).
   230  
   231  During development, the [fast_build.sh] script can be used to quickly build and
   232  run tests for a single package or all packages.
   233  
   234  [How to Write Go Code: Testing]: https://golang.org/doc/code.html#Testing
   235  [Go's testing package]: https://golang.org/pkg/testing/
   236  [Best practices for writing ChromeOS unit tests]: https://chromium.googlesource.com/chromiumos/docs/+/main/testing/unit_tests.md
   237  [fast_build.sh]: modifying_tast.md#fast_build_sh
   238  
   239  ### Import
   240  
   241  Entries in import declaration must be grouped by empty line, and sorted in
   242  following order.
   243  
   244  - Standard library packages
   245  - Third-party packages
   246  - chromiumos/ packages
   247  
   248  In each group, entries must be sorted in the lexicographical order. For example:
   249  
   250  ```go
   251  import (
   252  	"context"
   253  	"fmt"
   254  
   255  	"github.com/godbus/dbus/v5"
   256  	"golang.org/x/sys/unix"
   257  
   258  	"go.chromium.org/tast/core/errors"
   259  	"go.chromium.org/tast-tests/cros/local/chrome"
   260  )
   261  ```
   262  
   263  Note that, although github.com and golang.org are different domains, they
   264  should be in a group.
   265  
   266  This is how `goimports --local=chromiumos/` sorts. It may be valuable to run
   267  the command. Note that, 1) the command preserves existing group. So, it may
   268  be necessary to remove empty lines in import() in advance, and 2) use the
   269  command to add/remove import entries based on the following code. The path
   270  resolution may require setting `GOPATH` properly.
   271  
   272  ## Test structure
   273  
   274  As seen in the test declaration above, each test is comprised of a single
   275  exported function that receives a [testing.State] struct. This is defined in the
   276  [Tast testing package] (not to be confused with [Go's `testing` package] for
   277  unit testing) and is used to log progress and report failures.
   278  
   279  [testing.State]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#State
   280  [Tast testing package]: https://chromium.googlesource.com/chromiumos/platform/tast/+/main/src/go.chromium.org/tast/core/testing/
   281  
   282  ### Startup and shutdown
   283  
   284  If a test requires the system to be in a particular state before it runs, it
   285  should include code that tries to get the system into that state if it isn't
   286  there already. Previous tests may have aborted mid-run; it's not safe to make
   287  assumptions that they undid all temporary changes that they made.
   288  
   289  Tests should also avoid performing unnecessary de-initialization steps on
   290  completion: UI tests should leave Chrome logged in at completion instead of
   291  restarting it, for example. Since later tests can't safely make assumptions
   292  about the initial state of the system, they'll need to e.g. restart Chrome again
   293  regardless, which takes even more time. In addition to resulting in a faster
   294  overall running time for the suite, leaving the system in a logged-in state
   295  makes it easier for developers to manually inspect it after running the test
   296  when diagnosing a failure.
   297  
   298  Note that tests should still undo atypical configuration that leaves the system
   299  in a non-fully-functional state, though. For example, if a test needs to
   300  temporarily stop a service, it should restart it before exiting.
   301  
   302  Use [defer] statements to perform cleanup when your test exits. `defer` is
   303  explained in more detail in the [Defer, Panic, and Recover] blog post.
   304  
   305  Put more succintly:
   306  
   307  > Assume you're getting a reasonable environment when your test starts, but
   308  > don't make assumptions about Chrome's initial state. Similarly, try to leave
   309  > the system in a reasonable state when you go, but don't worry about what
   310  > Chrome is doing.
   311  
   312  [defer]: https://tour.golang.org/flowcontrol/12
   313  [Defer, Panic, and Recover]: https://blog.golang.org/defer-panic-and-recover
   314  
   315  ### Contexts and timeouts
   316  
   317  Tast uses [context.Context] to implement timeouts. A test function takes as its
   318  first argument a [context.Context] with an associated deadline that expires when
   319  the test's timeout is reached. The default timeout is 2 minutes for [local tests]
   320  and 5 minutes for [remote tests]. The context's `Done` function returns a [channel]
   321  that can be used within a [select] statement to wait for expiration, after which
   322  the context's `Err` function returns a non-`nil` error.
   323  
   324  The [testing.Poll] function makes it easier to honor timeouts while polling for
   325  a condition:
   326  
   327  ```go
   328  if err := testing.Poll(ctx, func (ctx context.Context) error {
   329  	var url string
   330  	if err := MustSucceedEval(ctx, "location.href", &url); err != nil {
   331  		return testing.PollBreak(errors.Wrap(err, "failed to evaluate location.href"))
   332  	}
   333  	if url != targetURL {
   334  		return errors.Errorf("current URL is %s", url)
   335  	}
   336  	return nil
   337  }, &testing.PollOptions{Timeout: 10 * time.Second}); err != nil {
   338  	return errors.Wrap(err, "failed to navigate")
   339  }
   340  ```
   341  
   342  Return a [testing.PollBreak] error to stop the polling. Useful when you get an
   343  unexpected error inside the polling.
   344  
   345  Sleeping without polling for a condition is discouraged, since it makes tests
   346  flakier (when the sleep duration isn't long enough) or slower (when the duration
   347  is too long). If you really need to do so, use [testing.Sleep] to honor the context
   348  timeout.
   349  
   350  Any function that performs a blocking operation should take a [context.Context]
   351  as its first argument and return an error if the context expires before the
   352  operation finishes.
   353  
   354  Several blog posts discuss these patterns in more detail:
   355  
   356  *   [Go Concurrency Patterns: Context]
   357  *   [Go Concurrency Patterns: Timing out, moving on]
   358  
   359  Note: there is an old equivalent "golang.org/x/net/context" package, but for
   360  consistency, the built-in "context" package is preferred.
   361  
   362  > As a rule of thumb, a timeout should be **double of the expected worst case
   363  > performance**. If you're unsure, measure time multiple times in the worst case
   364  > scenario and double that. Do not use timeouts to catch performance
   365  > regressions. Instead consider writing a performance test.
   366  > When a test hits a timeout that was sufficient before, investigate why it hit
   367  > the timeout before increasing it.
   368  
   369  The performance and worst case scenario can be obtained using the [time
   370  calculation script]. It parses the test result logs to obtain the average and
   371  max time from various executions.
   372  
   373  [context.Context]: https://golang.org/pkg/context/
   374  [channel]: https://tour.golang.org/concurrency/2
   375  [local tests]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast/src/go.chromium.org/tast/coreinternal/bundle/local.go
   376  [remote tests]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast/src/go.chromium.org/tast/coreinternal/bundle/remote.go
   377  [select]: https://tour.golang.org/concurrency/5
   378  [testing.Poll]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#Poll
   379  [testing.PollBreak]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#PollBreak
   380  [testing.Sleep]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#Sleep
   381  [Go Concurrency Patterns: Context]: https://blog.golang.org/context
   382  [Go Concurrency Patterns: Timing out, moving on]: https://blog.golang.org/go-concurrency-patterns-timing-out-and
   383  [time calculation script]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast-tests/tools/test_time_calculation.py
   384  
   385  ### Reserve time for clean-up task
   386  
   387  For any function with a corresponding clean-up function, prefer using the [defer]
   388  statement to keep the two function calls close together (see the
   389  [Startup and shutdown](#startup-and-shutdown) section for detail):
   390  ```go
   391  a := pkga.NewA(ctx, ...)
   392  defer func(ctx context.Context) {
   393    if err := a.CleanUp(ctx); err != nil {
   394      // ...
   395    }
   396  }(ctx)
   397  ```
   398  Before creating `A`, make sure that the clean-up function has sufficient time to
   399  run:
   400  ```go
   401  ctxForCleanUpA := ctx
   402  ctx, cancel := ctxutil.Shorten(ctx, pkga.TimeForCleanUpA)
   403  defer cancel()
   404  a := pkga.NewA(ctx, ...)
   405  defer func(ctx context.Context) {
   406    if err := a.CleanUp(ctx); err != nil {
   407      // ...
   408    }
   409  }(ctxForCleanUpA)
   410  ```
   411  
   412  It [ctxutil.Shorten]s `ctx` before calling `pkga.NewA` to ensure that after
   413  `pkga.NewA()`, `a.CleanUp()` still has time to perform the clean-up. Note that
   414  `pkga` should provide `TimeForCleanUpA` constant for its callers to reserve time
   415  for `a.CleanUp()`.
   416  Also, instead of assigning the shortened `ctx` to `sCtx`, it copies the original
   417  `ctx` to `ctxForCleanUpA` before shortening it. It is because we want to use
   418  `ctx` for the main logic and leave the longer name for the clean-up logic.
   419  
   420  Another approach was used but discouraged now:
   421  ```go
   422  a := pkga.NewA(ctx, ...)
   423  defer func(ctx context.Context) {
   424    if err := a.CleanUp(ctx); err != nil {
   425      // ...
   426    }
   427  }(ctx)
   428  ctx, cancel := a.ReserveForCleanUp(ctx)
   429  defer cancel()
   430  ```
   431  The reason why it is discouraged is because it needs `pkga.NewA()` to shorten
   432  `ctx` at the beginning of the function to ensure that it leaves enough time for
   433  `a.CleanUp()` to call.
   434  
   435  [ctxutil.Shorten]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/ctxutil#Shorten
   436  
   437  ### Concurrency
   438  
   439  Concurrency is rare in integration tests, but it enables doing things like
   440  watching for a D-Bus signal that a process emits soon after being restarted. It
   441  can also sometimes be used to make tests faster, e.g. by restarting multiple
   442  independent Upstart jobs simultaneously.
   443  
   444  The preferred way to synchronize concurrent work in Go programs is by passing
   445  data between [goroutines] using a [channel]. This large topic is introduced in
   446  the [Share Memory by Communicating] blog post, and the [Go Concurrency Patterns]
   447  talk is also a good summary. [The Go Memory Model] provides guarantees about the
   448  effects of memory reads and writes across goroutines.
   449  
   450  [goroutines]: https://tour.golang.org/concurrency/1
   451  [Share Memory by Communicating]: https://blog.golang.org/share-memory-by-communicating
   452  [Go Concurrency Patterns]: https://talks.golang.org/2012/concurrency.slide
   453  [The Go Memory Model]: https://golang.org/ref/mem
   454  
   455  ### Scoping and shared code
   456  
   457  Global variables in Go are [scoped at the package level] rather than the file
   458  level:
   459  
   460  > The scope of an identifier denoting a constant, type, variable, or function
   461  > ... declared at top level (outside any function) is the package block.
   462  
   463  As such, all tests within a package like `platform` or `ui` share the same
   464  namespace. It is ok to declare top level unexported symbols
   465  (e.g. functions, constants, etc), but please be careful of conflicts. Also,
   466  please avoid referencing identifiers declared in other files; otherwise
   467  `repo upload` will fail with lint errors.
   468  
   469  If you need to share functionality between tests in the same package, please
   470  introduce a new descriptively-named subpackage; see e.g. the [chromecrash]
   471  package within the `ui` package, used by the [ui.ChromeCrashLoggedIn] and
   472  [ui.ChromeCrashNotLoggedIn] tests. Subpackages are described in more detail
   473  later in this document. Importing a subpackage is allowed only in the category
   474  package containing it; otherwise `repo upload` will fail with lint errors.
   475  
   476  [scoped at the package level]: https://golang.org/ref/spec#Declarations_and_scope
   477  [chromecrash]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/chromecrash/
   478  [ui.ChromeCrashLoggedIn]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/chrome_crash_logged_in.go
   479  [ui.ChromeCrashNotLoggedIn]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/chrome_crash_not_logged_in.go
   480  
   481  ### Test consolidation
   482  
   483  Much praise has been written for verifying just one thing per test. A quick
   484  sampling of internal links:
   485  
   486  *   [TotT 227]
   487  *   [TotT 324]
   488  *   [TotT 339]
   489  *   [TotT 520]
   490  *   [Unit Testing Best Practices Do's and Don'ts]
   491  
   492  While this is sound advice for fast-running, deterministic unit tests, it isn't
   493  necessarily always the best approach for integration tests:
   494  
   495  *   There are unavoidable sources of non-determinism in ChromeOS integration
   496      tests. DUTs can experience hardware or networking issues, and flakiness
   497      becomes more likely as more tests are run.
   498  *   When a lengthy setup process is repeated by many tests in a single suite,
   499      lab resources are consumed for a longer period of time and other testing is
   500      delayed.
   501  
   502  If you need to verify multiple related aspects of a single feature that requires
   503  a time-consuming setup process like logging in to Chrome, starting Android, or
   504  launching a container, it's often preferable to write a single test that just
   505  does the setup once and then verifies all aspects of the feature. As described
   506  in the [Errors and Logging] section, multiple errors can be reported by a single
   507  test, so coverage need not be reduced when tests are consolidated and an early
   508  expectation fails.
   509  
   510  For lightweight testing that doesn't need to interact with Chrome or restart
   511  services, it's fine to use fine-grained tests — there's almost no per-test
   512  overhead in Tast; the overhead comes from repeating the same slow operations
   513  _within_ multiple tests.
   514  
   515  *** aside
   516  If all the time-consuming setup in your test suite is covered by a tast
   517  [fixtures], then splitting your test into multiple fine-grained tests
   518  will incur negligible overhead.
   519  ***
   520  
   521  [TotT 227]: http://go/tott/227
   522  [TotT 324]: http://go/tott/324
   523  [TotT 339]: http://go/tott/339
   524  [TotT 520]: http://go/tott/520
   525  [Unit Testing Best Practices Do's and Don'ts]: http://go/unit-test-practices#behavior-testing-dos-and-donts
   526  [Errors and Logging]: #errors-and-logging
   527  [fixtures]: #Fixtures
   528  
   529  ### Device dependencies
   530  
   531  A Tast test either passes (by reporting zero errors) or fails (by reporting one
   532  or more errors, timing out, or panicking). If a test requires functionality that
   533  isn't provided by the DUT, the test is skipped entirely.
   534  
   535  Avoid writing tests that probe the DUT's capabilities at runtime, e.g.
   536  
   537  ```go
   538  // WRONG: Avoid testing for software or hardware features at runtime.
   539  func CheckCamera(ctx context.Context, s *testing.State) {
   540      if !supports720PCamera() {
   541          s.Log("Skipping test; device unsupported")
   542          return
   543      }
   544      // ...
   545  }
   546  ```
   547  
   548  This approach results in the test incorrectly passing even though it actually
   549  didn't verify anything. (Tast doesn't let tests report an "N/A" state at runtime
   550  since it would be slower than skipping the test altogether and since it will
   551  prevent making intelligent scheduling decisions in the future about where tests
   552  should be executed.)
   553  
   554  Instead, specify [software dependencies] when declaring tests:
   555  
   556  ```go
   557  // OK: Specify dependencies when declaring the test.
   558  func init() {
   559      testing.AddTest(&testing.Test{
   560          Func: CheckCamera,
   561          SoftwareDeps: []string{"camera_720p", "chrome"},
   562          // ...
   563      })
   564  }
   565  ```
   566  
   567  The above document describes how to define new dependencies.
   568  
   569  Also, there is an API Features which allows tests to get information regarding
   570  DUT features. However, it is purely used for informational purpose only. Do not
   571  use it to alter test behavior. Use it for only for informational purpose. Use
   572  [parameterized tests] for tests to have different behavior for different
   573  DUT features.
   574  
   575  If a test depends on the DUT being in a specific configurable state (e.g. tablet
   576  mode), it should put it into that state. For example, [chrome.ExtraArgs] can be
   577  passed to [chrome.New] to pass additional command-line flags (e.g.
   578  `--force-tablet-mode=touch_view`) when starting Chrome.
   579  
   580  The [tast-users mailing list] is a good place to ask questions about test
   581  dependencies.
   582  
   583  [chrome.ExtraArgs]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast-tests.git/src/go.chromium.org/tast-tests/cros/local/chrome#ExtraArgs
   584  [chrome.New]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast-tests.git/src/go.chromium.org/tast-tests/cros/local/chrome#New
   585  [tast-users mailing list]: https://groups.google.com/a/chromium.org/forum/#!forum/tast-users
   586  [parameterized tests]: #Parameterized-tests
   587  
   588  ### Fixtures
   589  
   590  Sometimes a lengthy setup process (e.g. restarting Chrome and logging in, which
   591  takes at least 6-7 seconds) is needed by multiple tests. Rather than running the
   592  same setup for each of those tests, tests can declare the shared setup, which is
   593  named "fixtures" in Tast.
   594  
   595  Tests sharing the same fixture run consecutively. A fixture implements several
   596  _lifecycle methods_ that are called by the framework as it executes tests
   597  associated with the fixture. `SetUp()` of the fixture runs once just before the
   598  first of them starts, and `TearDown()` is called once just after the last of
   599  them completes. `Reset()` runs after each but the last test to roll back changes
   600  a test made to the environment.
   601  
   602  * Fixture `SetUp()`
   603  * Test 1 runs
   604  * Fixture `Reset()`
   605  * Test 2 runs
   606  * Fixture `Reset()`
   607  * ...
   608  * Fixture `Reset()`
   609  * Test N runs
   610  * Fixture `TearDown()`
   611  
   612  `Reset()` should be a light-weight and idempotent operation. If it fails
   613  (returns a non-nil error), framework falls back to `TearDown()` and `SetUp()` to
   614  completely restart the fixture.
   615  Tests should not leave too much change on system environment, so that the next
   616  `Reset()` does not fail.
   617  
   618  *** aside
   619  Currently Reset errors do not mark a test as failed. We plan to change this
   620  behavior in the future ([b/187795248](http://b/187795248)).
   621  ***
   622  
   623  Fixtures also have `PreTest()` and `PostTest()` methods, which run before and
   624  after each test. They get called with [`testing.FixtTestState`] with which you
   625  can report errors as a test. It's a good place to set up logging for individual
   626  test for example.
   627  
   628  For details of these fixture lifecycle methods, please see the GoDoc
   629  [`testing.FixtureImpl`].
   630  
   631  Each test can declare its fixture by setting [`testing.Test.Fixture`] an fixture
   632  name. The fixture's `SetUp()` returns an arbitrary value that can be obtained by
   633  calling `s.FixtValue()` in the test. Because `s.FixtValue()` returns an
   634  `interface{}`, type assertion is needed to cast it to the actual type.
   635  However, `s.FixtValue()` will always return nil when local tests/fixtures
   636  try to access values from remote fixtures because Tast does not know the actual
   637  types of fixture values to deserialize them. Therefore, there is another
   638  function `s.FixtFillValue(v, any)` which requires user to pass in a pointer,
   639  and it will store the deserialized result in the value pointed to by pointer.
   640  
   641  Fixtures are composable. A fixture can declare its parent fixture with
   642  `testing.Fixture.Parent`. Parent's `SetUp()` is executed before the fixture's
   643  `SetUp()` is executed, parent's `TearDown()` is executed after the fixtures's
   644  `TearDown()`, and so on. Fixtures can use the parent's value in the same way
   645  tests use it.
   646  
   647  Local tests/fixtures can depend on a remote fixture if they live in test bundles
   648  with the same name (e.g. local `cros` and remote `cros`).
   649  
   650  Fixtures are registered by calling [`testing.AddFixture`] with [`testing.Fixture`]
   651  struct in `init()`. `testing.Fixture.Name` specifies the fixture name,
   652  `testing.Fixture.Impl` specifies implementation of the fixture,
   653  `testing.Fixture.Parent` specifies the parent fixture if any,
   654  `testing.Fixture.SetUpTimeout` and the like specify methods' timeout,
   655  and the other fields are analogous to `testing.Test`.
   656  
   657  Fixtures can be registered outside bundles directory. It's best to initialize
   658  and register fixtures outside bundles if it is shared by tests in multiple
   659  categories.
   660  
   661  #### Examples
   662  
   663  * Rather than calling [chrome.New] at the beginning of each test, tests can
   664  declare that they require a logged-in Chrome instance by setting
   665  [`testing.Test.Fixture`] to "[chromeLoggedIn]" in `init()`. This enables Tast to
   666  just perform login once and then share the same Chrome instance with all tests
   667  that specify the fixture. See the [chromeLoggedIn] documentation for more
   668  details, and [example.ChromeFixture] for a test using the fixture.
   669  
   670  * If you want a new Chrome fixture with custom options, call
   671  [`testing.AddFixture`] from [chrome/fixture.go] with different options, and give
   672  it a unique name.
   673  
   674  #### Theory behind fixtures
   675  
   676  On designing composable fixtures, understanding the theory behind fixtures might
   677  help.
   678  
   679  Let us think of a space representing all possible system states. A fixture's
   680  purpose is to change the current system state to be in a certain subspace. For
   681  example, the fixture [chromeLoggedIn]'s purpose is to provide a clean
   682  environment similar to soon after logging into a Chrome session. This can be
   683  rephased that there's a subspace where "the system state is clean similar to
   684  soon after logging into a Chrome session" and the fixture's designed to change
   685  the system state to some point inside the subspace.
   686  
   687  To denote these concepts a bit formally: let `U` be a space representing all
   688  possible system states. Let `f` be a function that maps a fixture to its target
   689  system state subspace. Then, for any fixture `X`, `f(X) ⊆ U`. Note that `f(F)`
   690  is a subspace of `U`, not a point in `U`; there can be some degrees of freedom
   691  in a resulting system state.
   692  
   693  A fixture's property is as follows: if a test depends on a fixture `F` directly
   694  or indirectly, it can assume that the system state is in `f(F)` on its start.
   695  This also applies to fixtures: if a fixture depends on a fixture `F` directly or
   696  indirectly, it can assume that the system state is in `f(F)` on its setup.
   697  
   698  To fulfill this property, all fixtures should satisfy the following rule: if a
   699  fixture `X` has a child fixture `Y`, then `f(X) ⊇ f(Y)`. Otherwise, calling
   700  `Y`'s reset may put the system state to one not accepted by `X`, failing to
   701  fulfill the aforementioned property.
   702  
   703  #### Preconditions
   704  
   705  Preconditions, predecessor of fixtures, are not recommended for new tests.
   706  
   707  [`testing.Fixture`]: https://pkg.go.dev/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/coreinternal/testing#Fixture
   708  [`testing.FixtureImpl`]: https://pkg.go.dev/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/coreinternal/testing#FixtureImpl
   709  [`testing.FixtTestState`]: https://pkg.go.dev/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/coreinternal/testing#FixtTestState
   710  [chrome.New]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast-tests.git/src/go.chromium.org/tast-tests/cros/local/chrome#New
   711  [chromeLoggedIn]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast-tests/src/go.chromium.org/tast-tests/cros/local/chrome/fixture.go
   712  [`testing.Test.Fixture`]: https://pkg.go.dev/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/coreinternal/testing#Test.Fixture
   713  [chrome/fixture.go]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast-tests/src/go.chromium.org/tast-tests/cros/local/chrome/fixture.go
   714  [example.ChromeFixture]: https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast-tests/src/go.chromium.org/tast-tests/cros/local/bundles/cros/example/chrome_fixture.go
   715  [`testing.AddFixture`]: https://pkg.go.dev/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#AddFixture
   716  
   717  ## Common testing patterns
   718  
   719  ### Table-driven tests
   720  
   721  It is sometimes the case that multiple scenarios with very slight differences
   722  should be tested. In this case you can write a [table-driven test], which is a
   723  common pattern in Go unit tests. [testing.State.Run] can be used to start a
   724  subtest.
   725  
   726  ```go
   727  for _, tc := range []struct {
   728      format   string
   729      filename string
   730      duration time.Duration
   731  }{
   732      {
   733          format:   "VP8",
   734          filename: "sample.vp8",
   735          duration: 3 * time.Second,
   736      },
   737      {
   738          format:   "VP9",
   739          filename: "sample.vp9",
   740          duration: 3 * time.Second,
   741      },
   742      {
   743          format:   "H.264",
   744          filename: "sample.h264",
   745          duration: 5 * time.Second,
   746      },
   747  } {
   748      s.Run(ctx, tc.format, func(ctx context.Context, s *testing.State) {
   749          if err := testPlayback(ctx, tc.filename, tc.duration); err != nil {
   750              s.Error("Playback test failed: ", err)
   751          }
   752      })
   753  }
   754  ```
   755  
   756  [table-driven test]: https://github.com/golang/go/wiki/TableDrivenTests
   757  [testing.State.Run]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#State.Run
   758  
   759  ## Errors and logging
   760  
   761  The [testing.State] struct provides functions that tests may use to report their
   762  status:
   763  
   764  *   `Log` and `Logf` record informational messages about the test's progress.
   765  *   `Error` and `Errorf` record errors and mark the test as failed but allow it
   766      to continue, similar to [Google Test]'s `EXPECT_` set of macros. Multiple
   767      errors may be reported by a single test.
   768  *   `Fatal` and `Fatalf` record errors and stop the test immediately, similar to
   769      the `ASSERT_` set of macros.
   770  
   771  Note that higher-level functions for stating expectations and assertions are not
   772  provided; this was a conscious decision. See ["Where is my favorite helper
   773  function for testing?"] from the [Go FAQ]. That answer refers to [Go's testing
   774  package] rather than Tast's, but the same reasoning and suggestions are
   775  applicable to Tast tests.
   776  
   777  [Google Test]: https://github.com/google/googletest
   778  ["Where is my favorite helper function for testing?"]: https://golang.org/doc/faq#testing_framework
   779  
   780  ### When to log
   781  
   782  When you're about to do something that could take a while or even hang, log a
   783  message using `Log` or `Logf` first. This both lets developers know what's
   784  happening when they run your test interactively and helps when looking at logs
   785  to investigate timeout failures.
   786  
   787  On the other hand, avoid logging unnecessary information that would clutter the
   788  logs. If you want to log a verbose piece of information to help determine the
   789  cause of an error, only do it after the error has occurred. Also, if you are
   790  interested in which part of a test is time-consuming, please see the
   791  [Reporting timing] section for details.
   792  
   793  See the [fmt package]'s documentation for available "verbs".
   794  
   795  [fmt package]: https://golang.org/pkg/fmt/
   796  [Reporting timing]: #Reporting-timing
   797  
   798  <a name="log-vs-logf"></a>
   799  
   800  ### Log/Error/Fatal vs. Logf/Errorf/Fatalf
   801  
   802  `Log`, `Error`, and `Fatal` should be used in conjunction with a single string
   803  literal or when passing a string literal followed by a single value:
   804  
   805  ```go
   806  s.Log("Doing something slow")
   807  s.Log("Loading ", url)
   808  s.Error("Encountered an error: ", err)
   809  s.Fatal("Everything is broken: ", err)
   810  ```
   811  
   812  `Logf`, `Errorf`, and `Fatalf` should only be used in conjunction with `printf`-style
   813  format strings:
   814  
   815  ```go
   816  s.Logf("Read %q from %v", data, path)
   817  s.Errorf("Failed to load %v: %v", url, err)
   818  s.Fatalf("Got invalid JSON object %+v", obj)
   819  ```
   820  
   821  When concatenating a string and a value using default formatting, use
   822  `s.Log("Some value: ", val)` rather than the more-verbose
   823  `s.Logf("Some value: %v", val)`.
   824  
   825  The same considerations apply to `testing.ContextLog` vs. `testing.ContextLogf`.
   826  
   827  <a name="error-pkg"></a>
   828  
   829  ### Error construction
   830  
   831  To construct new errors or wrap other errors, use the [go.chromium.org/tast/core/errors]
   832  package rather than standard libraries (`errors.New`, `fmt.Errorf`) or any other
   833  third-party libraries. It records stack traces and chained errors, and leaves
   834  nicely formatted logs when tests fail.
   835  
   836  To construct a new error, use [errors.New] or [errors.Errorf].
   837  
   838  ```go
   839  errors.New("process not found")
   840  errors.Errorf("process %d not found", pid)
   841  ```
   842  
   843  To construct an error by adding context to an existing error, use [errors.Wrap] or [errors.Wrapf].
   844  
   845  ```go
   846  errors.Wrap(err, "failed to connect to Chrome browser process")
   847  errors.Wrapf(err, "failed to connect to Chrome renderer process %d", pid)
   848  ```
   849  
   850  To examine sentinel errors which may be `Wrap`ed, use [errors.Is] or
   851  [errors.As]. The usage is the same as the functions with the same names in the
   852  official errors package.
   853  
   854  Sometimes you may want to define custom error types, for example, to inspect and
   855  react to errors. In that case, embed `*errors.E` to your custom error struct.
   856  
   857  ```go
   858  type CustomError struct {
   859      *errors.E
   860  }
   861  
   862  if err := doSomething(); err != nil {
   863      return &CustomError{E: errors.Wrap(err, "something failed")}
   864  }
   865  ```
   866  
   867  It is recommended to wrap when you cross package boundary, which represents
   868  some kind of barrier beneath which everything is an implementation detail.
   869  Otherwise it is fine to return an error without wrapping, if you can't really
   870  add much context to make debugging easier. Use your best judgement to decide
   871  wrap or not.
   872  
   873  Following quotes from
   874  *[The Go programming language] 5.4.1 Error-Handling Strategies*
   875  are useful to design good errors:
   876  
   877  > - When designing error messages, be deliberate, so that each one is a meaningful description of the problem with sufficient and relevant detail.
   878  > - In general, the call `f(x)` is responsible for reporting the attempted operation `f` and the argument value `x` as they relate to the context of the error.
   879  > - The caller is responsible for adding further information that it has but the call `f(x)` does not.
   880  
   881  [go.chromium.org/tast/core/errors]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors
   882  [errors.New]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#New
   883  [errors.Errorf]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#Errorf
   884  [errors.Wrap]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#Wrap
   885  [errors.Wrapf]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#Wrapf
   886  [errors.Is]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#Is
   887  [errors.As]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors#As
   888  [The Go programming language]: https://www.gopl.io/
   889  
   890  ### Formatting
   891  
   892  <a name="error-fmt"></a>
   893  
   894  Please follow [Go's error string conventions] when producing `error` values.
   895  
   896  > Error strings should not be capitalized (unless beginning with proper nouns or
   897  > acronyms) or end with punctuation, since they are usually printed following
   898  > other context.
   899  
   900  For example:
   901  
   902  ```go
   903  if err := doSomething(id); err != nil {
   904  	return errors.Wrapf(err, "doing something to %q failed", id)
   905  }
   906  ```
   907  
   908  <a name="log-fmt"></a>
   909  
   910  Log and error messages printed by tests via `testing.State`'s `Log`, `Logf`,
   911  `Error`, `Errorf`, `Fatal`, or `Fatalf` methods, or via `testing.ContextLog` or
   912  `testing.ContextLogf`, should be capitalized phrases without any trailing
   913  punctuation that clearly describe what is about to be done or what happened:
   914  
   915  ```go
   916  s.Log("Asking Chrome to log in")
   917  ...
   918  if err != nil {
   919  	s.Fatal("Failed to log in: ", err)
   920  }
   921  s.Logf("Logged in as user %v with ID %v", user, id)
   922  ```
   923  
   924  <a name="common-fmt"></a>
   925  
   926  In all cases, please avoid multiline strings since they make logs difficult to
   927  read. To preserve multiline output from an external program, please write it to
   928  an [output file] instead of logging it.
   929  
   930  When including a path, URL, or other easily-printable value in a log message or
   931  an error, omit leading colons or surrounding quotes:
   932  
   933  ```go
   934  s.Logf("Trying to log in up to %d time(s)", numLogins)
   935  errors.Errorf("%v not found", path)
   936  ```
   937  
   938  Use quotes when including arbitrary data that may contain hard-to-print
   939  characters like spaces:
   940  
   941  ```go
   942  s.Logf("Successfully read %q from %v", data, path)
   943  ```
   944  
   945  Use a colon followed by a space when appending a separate clause that contains
   946  additional detail (typically an error):
   947  
   948  ```go
   949  s.Error("Failed to log in: ", err)
   950  ```
   951  
   952  Semicolons are appropriate for joining independent clauses:
   953  
   954  ```go
   955  s.Log("Attempt failed; trying again")
   956  ```
   957  
   958  [Go's error string conventions]: https://github.com/golang/go/wiki/CodeReviewComments#error-strings
   959  [output file]: #Output-files
   960  
   961  ### Support packages
   962  
   963  Support packages should not record test failures directly. Instead, return
   964  `error` values (using the [errors package]) and allow tests to decide
   965  how to handle them. Support packages' exported functions should typically take
   966  [context.Context] arguments and use them to return an error early when the
   967  test's deadline is reached and to log informative messages using
   968  `testing.ContextLog` and `testing.ContextLogf`.
   969  
   970  Similarly, support packages should avoid calling `panic` when errors are
   971  encountered. When a test is running, `panic` has the same effect as `State`'s
   972  `Fatal` and `Fatalf` methods: the test is aborted immediately. Returning an
   973  `error` gives tests the ability to choose how to respond.
   974  
   975  The [Error handling and Go] and [Errors are values] blog posts offer guidance on
   976  using the `error` type.
   977  
   978  [errors package]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/errors
   979  [Error handling and Go]: https://blog.golang.org/error-handling-and-go
   980  [Errors are values]: https://blog.golang.org/errors-are-values
   981  
   982  ### Test subpackages
   983  
   984  The above guidelines do not necessarily apply to test subpackages that are
   985  located in subdirectories below test files. If a subpackage actually contains
   986  the test implementation (typically because it's shared across several tests),
   987  it's okay to pass `testing.State` to it so it can report test errors itself.
   988  
   989  Subpackages are typically aware of how they will be used, so an argument can be
   990  made for letting them abort testing using `Fatal` or even `panic` in cases where
   991  it improves code readability (e.g. for truly exceptional cases like I/O
   992  failures). Use your best judgement.
   993  
   994  Note that it's still best to practice [information hiding] and pass only as much
   995  data is needed. Avoid passing `testing.State` when it's not actually necessary:
   996  
   997  *   If a function just needs the output directory, pass a path.
   998  *   If a function just needs to log its progress, pass a `context.Context` so it
   999      can call `testing.ContextLog`.
  1000  
  1001  [information hiding]: https://en.wikipedia.org/wiki/Information_hiding
  1002  
  1003  ### Reporting timing
  1004  
  1005  The [timing package] can be used to measure and report the time taken by
  1006  different "stages" of a test. It helps you identify which stage takes an
  1007  unexpectedly long time to complete.
  1008  
  1009  An example to time a test with two stages:
  1010  
  1011  ```go
  1012  func TestFoo(ctx context.Context, s *testing.State) {
  1013      // Tast framework already adds a stage for the test function.
  1014      stageA(ctx)
  1015      stageB(ctx)
  1016  }
  1017  
  1018  func stageA(ctx context.Context) {
  1019      ctx, st := timing.Start(ctx, "stage_a")
  1020      defer st.End()
  1021      ...
  1022  }
  1023  
  1024  func stageB(ctx context.Context) {
  1025      ctx, st := timing.Start(ctx, "stage_b")
  1026      defer st.End()
  1027      ...
  1028  }
  1029  ```
  1030  
  1031  By default, the result will be written to `timing.json` (see [timing#Log.Write]
  1032  for details) in the Tast [results dir]. The above example will generate:
  1033  
  1034  ```json
  1035  [4.000, "example.TestFoo", [
  1036      [1.000, "stage_a"],
  1037      [3.000, "stage_b"]]]
  1038  ```
  1039  
  1040  [timing package]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/timing
  1041  [timing#Log.Write]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/timing#Log.Write
  1042  [results dir]: running_tests.md#Interpreting-test-results
  1043  
  1044  ### Logged in users home directory
  1045  
  1046  Within the scope of a test, it might be useful to put files in the users
  1047  Downloads directory or My Files directory. To achieve there are 2 helper methods
  1048  that calculate the logged in user's hash and return the path to either Downloads
  1049  or MyFiles. To use these, do the following:
  1050  
  1051  ```go
  1052  import "go.chromium.org/tast-tests/cros/local/cryptohome"
  1053  
  1054  downloadsPath, err := cryptohome.DownloadsPath(ctx, cr.NormalizedUser())
  1055  if err != nil {
  1056    s.Fatal("Failed to get users Download path: ", err)
  1057  }
  1058  ```
  1059  
  1060  An alternative `MyFilesPath` if you require the My Files location directly.
  1061  Please avoid using the `/home/chronos/user` path directly as these are being
  1062  deprecated.
  1063  ## Output files
  1064  
  1065  Tests can write output files that are automatically copied to the host system
  1066  that was used to initiate testing:
  1067  
  1068  ```go
  1069  func WriteOutput(s *testing.State) {
  1070  	if err := ioutil.WriteFile(filepath.Join(s.OutDir(), "my_output.txt"),
  1071  		[]byte("Here's my output!"), 0644); err != nil {
  1072  		s.Error(err)
  1073  	}
  1074  }
  1075  ```
  1076  
  1077  As described in the [Running tests] document, a test's output files are copied
  1078  to a `tests/<test-name>/` subdirectory within the results directory.
  1079  
  1080  [Running tests]: running_tests.md
  1081  
  1082  ### Performance measurements
  1083  
  1084  The [perf] package is provided to record the results of performance tests.  See
  1085  the [perf] documentation for more details.
  1086  
  1087  [perf]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast-tests.git/src/go.chromium.org/tast-tests/cros/common/perf
  1088  
  1089  ## Data files
  1090  
  1091  Tests can register ancillary data files that will be copied to the DUT and made
  1092  available while the test is running; consider a JavaScript file that Chrome
  1093  loads or a short binary audio file that is played in a loop, for example.
  1094  
  1095  ### Internal data files
  1096  
  1097  Small non-binary data files should be directly checked into a `data/`
  1098  subdirectory under the test package as _internal data files_. Prefix their names
  1099  by the test file's name (e.g. `data/user_login_some_data.txt` for a test file
  1100  named `user_login.go`) to make ownership obvious.
  1101  
  1102  Per the [Chromium guidelines for third-party code], place
  1103  (appropriately-licensed) data that wasn't created by Chromium developers within
  1104  a `third_party` subdirectory under the `data` directory.
  1105  
  1106  [Chromium guidelines for third-party code]: https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/adding_to_third_party.md
  1107  
  1108  ### External data files
  1109  
  1110  Larger data files like audio, video, or graphics files should be stored in
  1111  Google Cloud Storage and registered as _external data files_ to avoid
  1112  permanently bloating the test repository. External data files are not installed
  1113  to test images but are downloaded at run time by `local_test_runner` on DUT.
  1114  
  1115  To add external data files, put _external link files_ named
  1116  `<original-name>.external` in `data/` subdirectory whose content is JSON in the
  1117  [external link format].
  1118  
  1119  For example, a data file belonging to a test named `ui.UserLogin` in the default
  1120  `cros` bundle might be declared in `user_login_some_image.jpg.external` with the
  1121  following content:
  1122  
  1123  ```
  1124  {
  1125    "url": "gs://chromiumos-test-assets-public/tast/cros/ui/user_login_some_image_20181210.jpg",
  1126    "size": 12345,
  1127    "sha256sum": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  1128  }
  1129  ```
  1130  
  1131  > Old versions of external data files should be retained indefinitely in Google
  1132  > Cloud Storage so as to not break tests on older system images. Include the
  1133  > date as a suffix in the filename to make it easy to add a new version when
  1134  > needed, e.g. `user_login_data_20180812.bin`.
  1135  
  1136  If data files are produced as [build artifacts of ChromeOS], they can be also
  1137  used as external data files. However, build artifacts are available only for
  1138  ChromeOS images built by official builders; for developer builds, tests
  1139  requiring build artifacts will fail.
  1140  
  1141  An example external link file to reference a build artifact is below:
  1142  
  1143  ```
  1144  {
  1145    "type": "artifact",
  1146    "name": "license_credits.html"
  1147  }
  1148  ```
  1149  
  1150  To upload a file to Google Cloud Storage you can use the [`gsutil cp`] command.
  1151  
  1152  To list all uploaded versions of the file, use the `gsutil ls -a` command.
  1153  
  1154  External files are cached in two locations: /usr/local/share/tast/data_pushed on
  1155  the DUT and /tmp/tast/devserver on the host machine. To ensure the reproducibility
  1156  of tests and prevent stale cache data from being served, cloud storage files should
  1157  never be overwritten once they have been used in a CQ run or dry-run. If
  1158  overwriting a cloud storage file, remember to manually clear the cache folders
  1159  before running Tast tests to prevent stale files from being served.
  1160  
  1161  [external link format]: https://chromium.googlesource.com/chromiumos/platform/tast/+/main/src/go.chromium.org/tast/coreinternal/extdata/extdata.go
  1162  [example.DataFiles]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/example/data_files.go
  1163  [build artifacts of ChromeOS]: https://goto.google.com/cros-build-google-storage
  1164  [`gsutil cp`]: https://cloud.google.com/storage/docs/gsutil/commands/cp
  1165  
  1166  ### Internal vs. external
  1167  
  1168  As internal data files are much easier to view and modify than external data
  1169  files, it's usually better to check in textual data. Only store binaries as
  1170  external data.
  1171  
  1172  ### Executables
  1173  
  1174  If your test depends on outside executables, use Portage to build and package
  1175  those executables separately and include them in test ChromeOS system images.
  1176  Tast [intentionally](design_principles.md) does not support compiling or
  1177  deploying other packages that tests depend on.
  1178  
  1179  ### Sharing data files between test packages
  1180  
  1181  If a data file is needed by a support package that's used by tests in multiple
  1182  packages, it should be stored in a `data` subdirectory within the support
  1183  package and symlinked into each test package's `data` subdirectory. See the
  1184  [media_session_test.html] file used by the [mediasession package] and shared by
  1185  the [ui.PlayPauseChrome] and [arc.MediaSessionGain] tests, for example.
  1186  
  1187  [media_session_test.html]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/chrome/mediasession/data/media_session_test.html
  1188  [mediasession package]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast-tests.git/src/go.chromium.org/tast-tests/cros/local/chrome/mediasession
  1189  [ui.PlayPauseChrome]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/ui/play_pause_chrome.go
  1190  [arc.MediaSessionGain]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/local/bundles/cros/arc/media_session_gain.go
  1191  
  1192  ### Using data files in tests
  1193  
  1194  To register data files (regardless of whether they're checked into the test
  1195  repository or stored externally), in your test's `testing.AddTest` call, set the
  1196  `testing.Test` struct's `Data` field to contain a slice of data file names
  1197  (omitting the `data/` subdirectory, and the `.external` suffix for external data
  1198  files):
  1199  
  1200  ```go
  1201  testing.AddTest(&testing.Test{
  1202  	...
  1203  	Data: []string{"user_login_data.bin"},
  1204  	...
  1205  })
  1206  ```
  1207  
  1208  Later, within the test function, pass the same filename to [testing.State]'s
  1209  `DataPath` function to receive the path to the data file on the DUT:
  1210  
  1211  ```go
  1212  b, err := ioutil.ReadFile(s.DataPath("user_login_data.bin"))
  1213  ```
  1214  
  1215  See the [example.DataFiles] test for a complete example of using both local and
  1216  external data files.
  1217  
  1218  [example.DataFiles]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/bundles/cros/example/data_files.go
  1219  
  1220  ## Runtime variables
  1221  
  1222  Occasionally tests need to access dynamic or secret data (i.e. *out-of-band*
  1223  data), and that's when runtime variables become useful.
  1224  
  1225  ### Setting values
  1226  
  1227  To set runtime variables, add (possibly repeated) `-var=name=value` flags to
  1228  `tast run`.
  1229  
  1230  ### Accessing values
  1231  
  1232  Tast users can access runtime variables in two different ways. One way
  1233  is to declare global runtime variables which can be used by all testing
  1234  entities: services, fixtures, library functions and tests. Other entities
  1235  can use the variables by importing the package that defines the variables.
  1236  The other way is to declare test runtime variables which can be used by
  1237  fixture and tests.
  1238  
  1239  #### Global runtime variables (recommended for new code)
  1240  To declare a global runtime variable, use testing.RegisterVarString in an
  1241  entity. It should be a top-level variable declaration which should include
  1242  the name of the variable, default value and description. A duplicate of the
  1243  variable name in the same bundle will result in an error during registration
  1244  when a bundle starts.  Other files can access the variable by importing the
  1245  package that contains the declaration of the variable.
  1246  
  1247  Example:
  1248  
  1249  ```go
  1250  package example
  1251  
  1252  ...
  1253  
  1254  var exampleStrVar = testing.RegisterVarString(
  1255          "example.AccessVars.globalString",
  1256          "Default value",
  1257          "An example variable of string type",
  1258  )
  1259  
  1260  ...
  1261  
  1262  func AccessVars(ctx context.Context, s *testing.State) {
  1263          strVal := exampleStrVar.Value()
  1264  }
  1265  ```
  1266  
  1267  All variables should have the prefix “<package_name>.” to avoid name collision.
  1268  If one violates this convention, runtime error will happen.
  1269  
  1270  #### Test runtime variables
  1271  To declare test runtime variables, set the `testing.Test` struct's `Vars`
  1272  or `VarDeps` field inside your tests' `testing.AddTest` call.
  1273  `Vars` specifies optional runtime variables, and `VarDeps` specifies required
  1274  runtime variables to run the test. `VarDeps` should be the default choice,
  1275  and `Vars` should be used only when there's a fallback in case the variables
  1276  are missing.
  1277  
  1278  `Vars` and `VarDeps` should be an array literal of string literals or constants.
  1279  The test can later access the values by calling `s.Var` or `s.RequiredVar`
  1280  methods.
  1281  
  1282  For variables only used in a single test, prefix them with the test name
  1283  (e.g. `arc.Boot.foo` for a variable used only in `arc.Boot`).
  1284  For variables used from multiple tests, prefix them with the category name which mainly uses the variable
  1285  (e.g. `arc.foo`). Such variables can be used from any tests, not only ones in the same category.
  1286  
  1287  Variables without a dot in its name are called global variables. They are set by the framework, and individual tests don't have control over them.
  1288  Other variables should follow these rules:
  1289  
  1290  * Variable name should have the form of `foo.Bar.something` or `foo.something`, where `something` matches `[A-Za-z][A-Za-z0-9_]*`
  1291  * Only the test `foo.Bar` can access `foo.Bar.something`
  1292  * Any tests can access `foo.something`
  1293  
  1294  If one violates this convention, runtime error will happen.
  1295  
  1296  ### Skipping tests if a variable is not set.
  1297  
  1298  If you wish to skip tests if a variable is not set, your should use
  1299  `VarDeps` field inside those tests' `testing.AddTest` call regardless which
  1300  methods you choose to access the variable.
  1301  
  1302  When runtime variables in `VarDeps` are missing, by default the test fails
  1303  before it runs. `-maybemissingvars=<regex>` can be used to specify possibly
  1304  missing runtime variables and if every missing runtime variable in `VarDeps`
  1305  matches with the regex, the test is skipped.
  1306  
  1307  ### Secret variables
  1308  
  1309  This feature is for internal developers, who has access to `tast-tests-private` package.
  1310  
  1311  #### What is it
  1312  
  1313  This feature allows you to store secret key/value pairs in a private repository, and use them from public tests.
  1314  
  1315  For example, tests no longer have to be private just because they access secret GAIA credentials.
  1316  
  1317  #### How to do it
  1318  
  1319  Let `foo.Bar` be the test which should access secret username and password.
  1320  
  1321  If the variables are only used from the test, create the file `tast-tests-private/vars/foo.Bar.yaml` with the contents:
  1322  
  1323  ```Yaml
  1324  foo.Bar.user: someone@something.com
  1325  foo.Bar.password: whatever
  1326  ```
  1327  
  1328  If the values are shared among tests, create `foo.yaml` file instead.
  1329  
  1330  ```Yaml
  1331  foo.user: someone@something.com
  1332  foo.password: whatever
  1333  ```
  1334  
  1335  Then the test can access the variables just like normal variables assigned to the `tast` command with `-var`.
  1336  Secret variables cannot be used to define global variables.
  1337  
  1338  **Don't log secrets in tests** to avoid possible data leakage.
  1339  
  1340  ```go
  1341  func init() {
  1342  	testing.AddTest(&testing.Test{
  1343  		Func:     Bar,
  1344  	...
  1345  		VarDeps: []string{"foo.Bar.user", "foo.Bar.password"},
  1346  		// or foo.user, foo.password
  1347  	})
  1348  }
  1349  
  1350  func Bar(ctx context.Context, s *testing.State) {
  1351  	user := s.RequiredVar("foo.Bar.user")
  1352  	...
  1353  }
  1354  ```
  1355  
  1356  See [example.SecretVars](https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/bundles/cros/example/secret_vars.go) for working example.
  1357  
  1358  #### Naming convention
  1359  
  1360  * The file defining `foo.Bar.something` should be `foo.Bar.yaml`
  1361  * The file defining `foo.something` should be `foo.yaml`
  1362  
  1363  If one violates this convention, Tast linter will complain. Please honor the linter errors.
  1364  
  1365  ## Parameterized tests
  1366  
  1367  When multiple scenarios with very slight differences should be tested, the most
  1368  common pattern is to write [table-driven tests]. However testing everything in
  1369  a single test is sometimes undesirable for several reasons:
  1370  
  1371  *   Tests should have different attributes. For example, we might want
  1372      to set some of them [critical] to avoid regressions, while keeping others
  1373      [informational] due to test flakiness.
  1374  *   Tests should declare different dependencies. For example, VP8 playback
  1375      test should declare the "hardware-accelerated VP8 decoding" hardware
  1376      dependency, while other playback tests should declare their respective
  1377      dependencies.
  1378  *   Test results should be reported separately. For example, video playback
  1379      performance tests may want to report performance metrics separately for
  1380      different video formats (VP8/VP9/H.264/...).
  1381  
  1382  In such cases, *parameterized tests* can be used to define multiple similar
  1383  tests with different test properties.
  1384  
  1385  To parameterize a test, specify a slice of [`testing.Param`] in the `Params`
  1386  field on test registration. `Params` should be a literal since test
  1387  registration should be [declarative]. If `Params` is non-empty,
  1388  `testing.AddTest` expands the the test into one or more tests corresponding to
  1389  each item in `Params` by merging `testing.Test` and [`testing.Param`] with the
  1390  rules described below.
  1391  
  1392  Here is an example of a parameterized test registration:
  1393  
  1394  ```go
  1395  func init() {
  1396      testing.AddTest(&testing.Test{
  1397          Func:     Playback,
  1398          Desc:     "Tests media playback",
  1399          Contacts: []string{"someone@chromium.org"},
  1400          Attr:     []string{"group:mainline"},
  1401          Params: []testing.Param{{
  1402              Name:      "vp8",
  1403              Val:       "sample.vp8",
  1404              ExtraData: []string{"sample.vp8"},
  1405              ExtraAttr: []string{"informational"},
  1406          }, {
  1407              Name:      "vp9",
  1408              Val:       "sample.vp9",
  1409              ExtraData: []string{"sample.vp9"},
  1410              // No ExtraAttr; this test is critical.
  1411          }, {
  1412              Name:              "h264",
  1413              Val:               "sample.h264",
  1414              ExtraSoftwareDeps: []string{"chrome_internal"}, // H.264 codec is unavailable on ChromiumOS
  1415              ExtraData:         []string{"sample.h264"},
  1416              ExtraAttr:         []string{"informational"},
  1417          }},
  1418      })
  1419  }
  1420  
  1421  func Playback(ctx context.Context, s *testing.State) {
  1422      filename := s.Param().(string)
  1423      if err := playback(ctx, filename); err != nil {
  1424          s.Fatal("Failed to playback: ", err)
  1425      }
  1426  }
  1427  ```
  1428  
  1429  `Name` in [`testing.Param`] is appended to the base test name with a leading dot
  1430  to compute the test name, just like `category.TestName.parameter_name`.
  1431  If `Name` is empty, the base test name is used as-is. `Name` should be in
  1432  `lower_snake_case` style. `Name` must be unique within a parameterized test.
  1433  
  1434  `Val` in [`testing.Param`] is an arbitrary value that can be accessed in the
  1435  test body via the `testing.State.Param` method. Since it returns the value as
  1436  `interface{}`, it should be type-asserted to the original type immediately.
  1437  All `Val` in a parameterized test must have the same type.
  1438  
  1439  `Pre` and `Timeout` in [`testing.Param`] are equivalent to those in
  1440  `testing.Test`. They can be set only if the corresponding fields in the base
  1441  test are not set.
  1442  
  1443  `Extra*` in [`testing.Param`] (such as `ExtraAttr`) contains items added to
  1444  their corresponding base test properties (such as `Attr`) to obtain the test
  1445  properties.
  1446  
  1447  Because test registration should be declarative as written in
  1448  [test registration], `Params` should be an array literal containing `Param`
  1449  struct literals. In each `Param` struct, `Name` should be a string literal with
  1450  `snake_case` name if present. `ExtraAttr`, `ExtraData`, `ExtraSoftwareDeps` and
  1451  `Pre` should follow the rule of the corresponding `Attr`, `Data` ,`SoftwareDeps`
  1452  and `Pre` in [test registration].
  1453  
  1454  See documentation of [`testing.Param`] for the full list of customizable
  1455  properties.
  1456  
  1457  [table-driven tests]: #Table_driven-tests
  1458  [critical]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/test_attributes.md
  1459  [informational]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/test_attributes.md
  1460  [`testing.Param`]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#Param
  1461  [declarative]: #Test-registration
  1462  [test registration]: #Test-registration
  1463  
  1464  ## Remote procedure calls with gRPC
  1465  
  1466  In many cases, remote tests have to run some Go functions on the DUT, possibly
  1467  calling some support libraries for local tests (e.g. the [chrome] package).
  1468  For this purpose, Tast supports defining, implementing, and calling into [gRPC]
  1469  services.
  1470  
  1471  For the general usage of gRPC-Go, see also the [official tutorial].
  1472  
  1473  [chrome]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/local/chrome/
  1474  [gRPC]: https://grpc.io
  1475  [official tutorial]: https://grpc.io/docs/tutorials/basic/go/
  1476  
  1477  ### Defining gRPC services
  1478  
  1479  gRPC services are defined as protocol buffer files stored under
  1480  `tast-tests/src/go.chromium.org/tast-tests/cros/services`. The directory is organized in the
  1481  similar way as test bundles at
  1482  `tast-tests/src/go.chromium.org/tast-tests/cros/{local,remote}/bundles`. Below is an example of
  1483  an imaginary gRPC service `arc.BootService`:
  1484  
  1485  ```
  1486  tast-tests/src/go.chromium.org/tast-tests/cros/services/
  1487    cros/                   ... test bundle name where this service is included
  1488      arc/                  ... service category name
  1489        gen.go              ... Go file containing go generate directives
  1490        boot_service.proto  ... gRPC service definition
  1491        boot_service.pb.go  ... generated gRPC bindings
  1492  ```
  1493  
  1494  gRPC services are defined in `.proto` files. `boot_service.proto` would look like:
  1495  
  1496  ```proto
  1497  syntax = "proto3";
  1498  
  1499  package tast.cros.arc;
  1500  
  1501  import "google/protobuf/empty.proto";
  1502  
  1503  option go_package = "go.chromium.org/tast-tests/cros/services/cros/arc";
  1504  
  1505  // BootService allows remote tests to boot ARC on the DUT.
  1506  service BootService {
  1507    // CheckBoot logs into a new Chrome session, starts ARC and waits for its
  1508    // successful boot.
  1509    rpc CheckBoot (CheckBootRequest) returns (google.protobuf.Empty) {}
  1510  }
  1511  
  1512  message CheckBootRequest {
  1513    enum AndroidImpl {
  1514      DEFAULT = 0;
  1515      CONTAINER = 1;
  1516      VM = 2;
  1517    }
  1518    // impl specifies which ARC implementation to use.
  1519    AndroidImpl impl = 1;
  1520  }
  1521  ```
  1522  
  1523  Protocol buffers files should follow the
  1524  [official protocol buffers style guide], as well as several Tast-specific
  1525  guidelines:
  1526  
  1527  *   **File names**: Name `.proto` files in the same way as [test `.go` files].
  1528      For example, a service named `TPMStressService` should be defined in
  1529      `tpm_stress_service.proto`.
  1530  *   **Package names**: Protocol buffer package name specified in the `package`
  1531      directive should be `tast.<bundle-name>.<category-name>`. Go package name
  1532      specified in the `option go_package` directive should be
  1533      `go.chromium.org/tast-tests/cros/services/<bundle-name>/<category-name>`.
  1534  *   **Service names**: Name services with `Service` suffix.
  1535  *   **Message names**: Method request/response messages should be named
  1536      `FooBarRequest`/`FooBarResponse`.
  1537  *   **Comments**: Write comments in the [godoc style] since these protocol
  1538      buffers are used only by Tast tests in Go.
  1539  
  1540  `gen.go` is a small file containing a [`go generate` directive] to regenerate
  1541  `.pb.go` files, looking like the following:
  1542  
  1543  ```go
  1544  // Copyright 2019 The ChromiumOS Authors
  1545  // Use of this source code is governed by a BSD-style license that can be
  1546  // found in the LICENSE file.
  1547  
  1548  //go:generate protoc -I . --go_out=plugins=grpc:../../../../.. boot_service.proto
  1549  
  1550  package arc
  1551  
  1552  // Run the following command in CrOS chroot to regenerate protocol buffer bindings:
  1553  //
  1554  // ~/trunk/src/platform/tast/tools/go.sh generate go.chromium.org/tast-tests/cros/services/cros/arc
  1555  ```
  1556  
  1557  To regenerate `.pb.go` files, run the command mentioned in the file in ChromeOS
  1558  chroot (remember to replace the last argument of the command with the path to
  1559  the directory containing the protocol buffer files). This has to be done
  1560  manually whenever `.proto` files are edited. Updated `.pb.go` files should be
  1561  included and submitted in CLs adding/modifying/deleting `.proto` files.
  1562  
  1563  [official protocol buffers style guide]: https://developers.google.com/protocol-buffers/docs/style
  1564  [test `.go` files]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#code-location
  1565  [test functions]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#code-location
  1566  [godoc style]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#documentation
  1567  [`go generate` directive]: https://golang.org/pkg/cmd/go/internal/generate/
  1568  
  1569  ### Implementing gRPC services
  1570  
  1571  gRPC service implementations should be placed at the same location as local
  1572  tests, i.e. `tast-tests/src/go.chromium.org/tast-tests/cros/local/bundles`. For example, an
  1573  imaginary `arc.BootService` would be implemented in
  1574  `tast-tests/src/go.chromium.org/tast-tests/cros/local/bundles/arc/boot_service.go`.
  1575  
  1576  gRPC services can be registered with [`testing.AddService`] by passing
  1577  [`testing.Service`] containing service descriptions. The most important field is
  1578  `Register`, specifying a function to register a gRPC service to [`grpc.Server`].
  1579  Below is an implementation of the `arc.BootService`:
  1580  
  1581  ```go
  1582  // tast-tests/src/go.chromium.org/tast-tests/cros/local/bundles/arc/boot_service.go
  1583  package arc
  1584  
  1585  func init() {
  1586      testing.AddService(&testing.Service{
  1587          Register: func(srv *grpc.Server, s *testing.ServiceState) {
  1588              pb.RegisterBootServiceServer(srv, &BootService{s})
  1589          },
  1590      })
  1591  }
  1592  
  1593  // BootService implements tast.cros.arc.BootService.
  1594  type BootService struct {
  1595      s *testing.ServiceState
  1596  }
  1597  
  1598  func (*BootService) CheckBoot(ctx context.Context, req *pb.CheckBootRequest) (*empty.Empty, error) {
  1599      ...
  1600  }
  1601  ```
  1602  
  1603  For consistency, please follow these guidelines on implementing gRPC services:
  1604  
  1605  *   **File names**: Name gRPC service implementation `.go` files in the exactly
  1606      same way as [test `.go` files]. For example, a service named
  1607      `TPMStressService` should be implemented in `tpm_stress_service.go`.
  1608      This means that gRPC implementation files always have `_service.go` suffix.
  1609  *   **Implementation type**: A type implementing gRPC service should have
  1610      exactly the same name as the service name. The type should be the only
  1611      exported symbol in the `_service.go` file. Exactly one gRPC service
  1612      implementation should be registered in a single file.
  1613  *   **Inter-file references**: Similarly to test files, `_service.go` file
  1614      should not refer symbols in different files in the same directory.
  1615      Consequently, a gRPC service has to be implemented in a single file.
  1616      If the file gets too long, please consider introducing a subpackage just
  1617      like tests.
  1618  
  1619  `context.Context` passed to a gRPC method can be used to call some of
  1620  `testing.Context*` functions:
  1621  
  1622  *   `testing.ContextLog`, `testing.ContextLogf`, `testing.ContextLogger` work
  1623      fine. Emitted logs are recorded as if they were emitted by a remote test
  1624      that called into a gRPC method.
  1625  *   `testing.ContextOutDir` returns a path to a temporary directory. Files saved
  1626      in the directory during a gRPC method call are copied back to the host
  1627      machine's test output directory, as if they were saved by a remote test that
  1628      called into a gRPC method. Note that this function does not allow gRPC
  1629      methods to read output files from a remote test nor previous gRPC method
  1630      calls. Files are overwritten in the case of name conflicts.
  1631  *   `testing.ContextSoftwareDeps` does not work. This function is planned to be
  1632      deprecated ([crbug.com/1135996]).
  1633  
  1634  `Register` function receives [`testing.ServiceState`] which you can keep in
  1635  a field of the struct type implementing the gRPC service. It allows the service
  1636  to access service-specific information, such as runtime variables and data files
  1637  (not implemented yet: [crbug.com/1027381]).
  1638  
  1639  [`testing.AddService`]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#AddService
  1640  [`testing.Service`]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#Service
  1641  [`grpc.Server`]: https://godoc.org/google.golang.org/grpc#Server
  1642  [test `.go` files]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#code-location
  1643  [`testing.ServiceState`]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/testing#ServiceState
  1644  [crbug.com/1135996]: https://crbug.com/1135996
  1645  [crbug.com/1027381]: https://crbug.com/1027381
  1646  
  1647  ### Calling gRPC services
  1648  
  1649  A remote test should declare in its metadata which gRPC services it will call
  1650  into. Undeclared gRPC method calls shall be rejected internally. For example,
  1651  an imaginary remote test `arc.RemoteBoot` would be declared as:
  1652  
  1653  ```go
  1654  func init() {
  1655      testing.AddTest(&testing.Test{
  1656          Func:         RemoteTest,
  1657          SoftwareDeps: []string{"chrome", "android_p"},
  1658          ServiceDeps:  []string{"tast.cros.arc.BootService"},
  1659      })
  1660  }
  1661  ```
  1662  
  1663  Call [`rpc.Dial`] in remote tests to establish a connection to the gRPC server.
  1664  On success, it returns a struct containing [`grpc.ClientConn`] with which
  1665  you can construct gRPC stubs.
  1666  
  1667  ```go
  1668  cl, err := rpc.Dial(ctx, s.DUT(), s.RPCHint())
  1669  if err != nil {
  1670      s.Fatal("Failed to connect to the RPC service on the DUT: ", err)
  1671  }
  1672  defer cl.Close(ctx)
  1673  
  1674  bc := pb.NewBootServiceClient(cl.Conn)
  1675  
  1676  req := pb.CheckBootRequest{Impl: pb.CheckBootRequest_VM}
  1677  var res empty.Empty
  1678  if err := bc.CheckBoot(ctx, &req, &res); err != nil {
  1679      ...
  1680  }
  1681  ```
  1682  
  1683  [`rpc.Dial`]: https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/go.chromium.org/tast/core/rpc#Dial
  1684  [`grpc.ClientConn`]: https://godoc.org/google.golang.org/grpc#ClientConn
  1685  
  1686  ### Panics in gRPC services
  1687  
  1688  If a gRPC call fails with "error reading from server: EOF", it may indicate the
  1689  service panicked. The panic message is not currently logged or propagated to
  1690  the caller. This issue is tracked in [b/187794185].
  1691  
  1692  [b/187794185]: https://buganizer.corp.google.com/issues/187794185
  1693  
  1694  ### Notes on designing gRPC services
  1695  
  1696  As with anything involving protos, when updating them, please make sure you
  1697  maintain compatibility with older versions of the proto, as it is possible that
  1698  you can have a new gRPC server with an old gRPC client, and vice versa. To do
  1699  this, just ensure that you follow the principles outlined in
  1700  [this](https://protobuf.dev/programming-guides/proto3/#updating) document.
  1701  
  1702  Tast's gRPC services don't necessarily have to provide general-purpose APIs.
  1703  It is perfectly fine to define gRPC services specific to a particular test case.
  1704  For example, one may want to write a local test which exercises some features,
  1705  and a remote test that performs the same testing *after rebooting the DUT*.
  1706  In this case, they can put the whole local test content to a subpackage, and
  1707  introduce a local test and a gRPC service both of which call into the
  1708  subpackage.
  1709  
  1710  [crbug.com/1027368]: https://crbug.com/1027368
  1711  
  1712  ## Companion DUTs (Multi-DUTs) Support
  1713  
  1714  Most tests are written to test against one DUT, but multiple DUTs are needed
  1715  for tests that are testing the interaction between two or more DUTs. Tast uses
  1716  companion DUTs feature to support those tests. Please notice that Tast
  1717  currently only support companion DUTs for remote tests, and they are not
  1718  accessible by local tests.
  1719  
  1720  ### Tast Companion DUT CLI
  1721  
  1722  Users can use the run flag -companiondut to specify a companion DUT to be used
  1723  in tests. The flag is repeatable so users can specify more than one companion
  1724  DUT. The value of the flag specifies a role and a dut address in this format,
  1725  <Role>:<Host>.
  1726  
  1727  #### Examples
  1728  
  1729  Here is an example of how a companion DUT is specified on the Tast command
  1730  line.  In this example, primary DUT has the address 127.0.0.1:2222 and the
  1731  companion DUT has the address 127.0.0.1:2223.
  1732  
  1733  ```
  1734  % tast run --companiondut=cd1:127.0.0.1:2223 127.0.0.1:2222 <tests>
  1735  ```
  1736  
  1737  ### Accessing Companion DUTs In A Remote Test
  1738  
  1739  Users can use the function testing.State.CompanionDUT to get the pointer to
  1740  dut.DUT of a companion DUT. The function take the role name of the companion
  1741  DUT as the input parameter.
  1742  
  1743  #### Examples
  1744  
  1745  ```
  1746  // CompanionDUTs ensures DUT and companion DUTs are accessible in test.
  1747  // Tast command line:
  1748  // tast run -build=true -companiondut=cd1:dut1 dut0 meta.CompanionDUTs
  1749  func CompanionDUTs(ctx context.Context, s *testing.State) {
  1750  	cl, err := rpc.Dial(ctx, s.DUT(), s.RPCHint(), "cros")
  1751  	if err != nil {
  1752  		s.Fatal("Failed to connect to the RPC service on the DUT: ", err)
  1753  	}
  1754  	defer cl.Close(ctx)
  1755  
  1756  	companionDUT := s.CompanionDUT("cd1")
  1757  	if companionDUT == nil {
  1758  		s.Fatal("Failed to get companion DUT cd1")
  1759  	}
  1760  	companionCl, err := rpc.Dial(ctx, companionDUT, s.RPCHint(), "cros")
  1761  if err != nil {
  1762  		s.Fatal("Failed to connect to the RPC service on the companion DUT: ", err)
  1763  	}
  1764  	defer companionCl.Close(ctx)
  1765  }
  1766  ```
  1767  
  1768  ### Software/Hardware Dependencies Of Companion DUTs
  1769  
  1770  Users can use HardwareDepsForAll and SoftwareDepsAll of testing.Test to
  1771  specify the hardware/software dependencies on all DUTs used in a test.
  1772  Furthermore, users can use HardwareDepsForAll and SoftwareDepsAll of
  1773  testing.Test to specify the ExtraHardwareDepsForAll and
  1774  ExtraSoftwareDepsForAll of testing.Param to specify the hardware/software
  1775  dependencies on all DUTs of a parameterized test.
  1776  
  1777  ### Example of Specifying Companion Dependencies In A Test
  1778  
  1779  ```
  1780  type Test struct {
  1781               …
  1782          // SoftwareDepsForAll lists software features of all DUTs that
  1783          // are required to run the test.
  1784          // It is a map of companion roles and software features.
  1785          // The role for primary DUT should be "".
  1786          // The primary DUT software dependency will be the union of
  1787          // SoftwareDeps and SoftwareDepsForAll[""].
  1788          // If any dependencies are not satisfied, the test will be skipped.
  1789          SoftwareDepsForAll map[string][]string
  1790  
  1791          // HardwareDepsForAll describes hardware features and setup of all
  1792          // DUTs that are required to run the test.
  1793          // It is a map of companion roles and hardware features.
  1794          // The role for primary DUT should be "".
  1795          // The primary DUT hardware dependency will be the union of
  1796          // HardwareDeps and HardwareDepsForAll[""].
  1797          // If any dependencies are not satisfied, the test will be skipped.
  1798          HardwareDepsForAll map[string]hwdep.Deps
  1799          …
  1800  }
  1801  ```
  1802  
  1803  #### Specifying Hardware/Software Dependencies Of Companion DUTs In Parameterized Test
  1804  
  1805  ```
  1806  type Param struct {
  1807          …
  1808  
  1809          // ExtraSoftwareDepsForAll lists software features of all DUTs
  1810          // that are required to run the test case for this param,
  1811          // in addition to SoftwareDepsForAll in the enclosing Test.
  1812          // The primary DUT software dependency will be the union of
  1813          // SoftwareDeps, SoftwareDepsForAll[""], ExtraSoftwareDeps and
  1814          // ExtraSoftwareDepsForAll[""].
  1815          // It is a map of companion roles and software features.
  1816          ExtraSoftwareDepsForAll map[string][]string
  1817  
  1818          // ExtraHardwareDepsForAll describes hardware features and setup
  1819          // companion DUTs that are required to run the test case for this param,
  1820          // in addition to HardwareDepsForAll in the enclosing Test.
  1821          // It is a map of companion roles and hardware features.
  1822          // The role for primary DUT should be ""
  1823          // The primary DUT hardware dependency will be the union of
  1824          // HardwareDeps, HardwareDepsForAll[""], ExtraHardwareDeps and
  1825          // ExtraHardwareDep and ExtraHardwareDepsForAll[""].
  1826          ExtraHardwareDepsForAll map[string]hwdep.Deps
  1827  }
  1828  ```
  1829  
  1830  ### Example of Specifying Companion Dependencies In A Test
  1831  
  1832  ```
  1833  func init() {
  1834          testing.AddTest(&testing.Test{
  1835                  Func:         CompanionDepsUsage,
  1836                  …
  1837                  SoftwareDeps: []string{"chrome"},
  1838                  SoftwareDepsForAll: map[string][]string{
  1839                      // Additional primary DUT dependency.
  1840                      // As a result, primary will have dependency on "lacros"
  1841                      "": []string{"lacros"},
  1842                      // Companion DUT 1 dependency.
  1843                      "cd1": []string{"chrome"},
  1844                  },
  1845                  HardwareDepsForAll: map[string]hwdep.Deps {
  1846                      // Companion DUT 1 dependency.
  1847                      "cd1": hwdep.D(hwdep.InternalDisplay()),
  1848                  },
  1849          })
  1850  }
  1851  ```
  1852  
  1853  ### Example of Specifying Companion Dependencies In Parameterized Tests
  1854  
  1855  ```
  1856  func init() {
  1857      testing.AddTest(&testing.Test{
  1858          Func:         CompanionDepsParamUsage,
  1859          …
  1860            SoftwareDeps: []string{"chrome"},
  1861            …
  1862            Params: []testing.Param{
  1863              {
  1864               …
  1865                Name: "P1",
  1866                ExtraSoftwareDepsAll: map[string][]string{
  1867                  "cd1": []string{ "android_p"},
  1868                },
  1869               },
  1870                ExtraHardwareDepsForAll: map[string]hwdep.Deps {
  1871                  "cd1": hwdep.D(hwdep.InternalDisplay()),
  1872              },
  1873              {
  1874                …
  1875                Name: "p2",
  1876                ExtraSoftwareDepsForAll: map[string][]string{
  1877                  "cd1": []string{ "android_vm"},
  1878                },
  1879               },
  1880                ExtraHardwareDepsForAll: map[string]hwdep.Deps {
  1881                  "cd1": hwdep.D(hwdep.InternalDisplay()),
  1882                },
  1883              },
  1884           },
  1885      })
  1886  }
  1887  ```
  1888  
  1889  
  1890  
  1891  
  1892  
  1893  ## Utilities
  1894  
  1895  Tast contains many utilities for common operations. Some of them are briefly
  1896  described below; see the package links for additional documentation and
  1897  examples.
  1898  
  1899  ### lsbrelease
  1900  
  1901  The [`lsbrelease`] package provides access to the fields in `/etc/lsb-release`.
  1902  Usually Tast tests are not supposed to that information to change their
  1903  behavior, so `lsbrelease` contains a list of packages that are allowed to use
  1904  it. Attempting to use `lsbrelease` in a package that is not in the allow list
  1905  will cause a panic.
  1906  
  1907  [`lsbrelease`]: https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/src/go.chromium.org/tast/core/lsbrelease/lsbrelease.go
  1908  
  1909  ### testexec
  1910  
  1911  The [`testexec`] package provides a convenient interface to run processes on
  1912  the DUT. It should be used instead of the standard `os/exec` package.
  1913  
  1914  [`testexec`]: https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/go.chromium.org/tast-tests/cros/common/testexec/testexec.go
  1915  
  1916  ## Use of third party libraries
  1917  
  1918  1. Add an ebuild to package the code as a Portage package in
  1919  [third_party/chromiumos-overlay], and they will effectively review third party
  1920  licensing ([example](
  1921  https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/1146070)).
  1922  2. Add the dependency to tast-build-deps ([example](
  1923  https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/1737396)).
  1924  Please send this CL to ebuild-reviews@ and tast-owners@.
  1925  
  1926  Tast doesn't have any official process to review third party libraries.
  1927  Just take usual precautions on introducing libraries, such as
  1928  
  1929  - Is the library popular?
  1930  - Is the author reliable? Do they respond to issues, solve bugs and accept pull requests?
  1931  - Is the API well-documented?
  1932  - Does the library cover all your requirements?
  1933  
  1934  If you are in doubt, please feel free to send your proposal to
  1935  tast-reviewers@google.com.
  1936  
  1937  When testing locally, remember to `cros_workon --host start tast-build-deps`
  1938  and `./update_chroot` to build Tast with your new dependencies.
  1939  
  1940  ### Dependencies with 9999 ebuilds
  1941  
  1942  Dependencies are picked up from the host, not any board. So if you have updated
  1943  a dependency with a 9999 ebuild, then you'll need to workon start it. For
  1944  example if you've added something to system_api:
  1945  ```
  1946  (cr) ~/chromiumos/src/scripts $ cros_workon --host start chromeos-base/system_api tast-build-deps
  1947  (cr) ~/chromiumos/src/scripts $ ./update_chroot
  1948  ```
  1949  
  1950  And cleanup after you're done with local changes:
  1951  ```
  1952  (cr) ~/chromiumos/src/scripts $ cros_workon --host stop chromeos-base/system_api tast-build-deps
  1953  ```
  1954  
  1955  [third_party/chromiumos-overlay]: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/main/dev-go/
  1956  
  1957  ### Test promotion process for mainline tests
  1958  
  1959  The group:mainline non-informational tests are run in ChromeOS lab for CQs.
  1960  
  1961  Please see the Google internal link go/tast-add-test (Googler only) for the
  1962  promotion process from informational to non-informational.
  1963  
  1964  [go/tast-add-test]: http://goto.google.com/tast-add-test
  1965