blob: bfba197a6e40a2e0dd57ce5a1bc2c58faa9da914 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package driver implements drivers to execute tests.
package driver
import (
"bufio"
"context"
"fmt"
"log"
"os/exec"
"strings"
"sync"
"chromiumos/lro"
"go.chromium.org/chromiumos/config/go/test/api"
"chromiumos/test/execution/cmd/cros-test/internal/common"
"chromiumos/test/execution/cmd/cros-test/internal/device"
"chromiumos/test/execution/cmd/cros-test/internal/tautoresults"
)
// TautoDriver runs Tauto and report its results.
type TautoDriver struct {
// logger provides logging service.
logger *log.Logger
// Long running operation manager
manager *lro.Manager
// operation name
op string
}
// NewTautoDriver creates a new driver to run tests.
func NewTautoDriver(logger *log.Logger) *TautoDriver {
return &TautoDriver{
logger: logger,
}
}
// Name returns the name of the driver.
func (td *TautoDriver) Name() string {
return "tauto"
}
// RunTests drives a test framework to execute tests.
func (td *TautoDriver) RunTests(ctx context.Context, resultsDir string, req *api.CrosTestRequest, tlwAddr string, tests []*api.TestCaseMetadata) (*api.CrosTestResponse, error) {
primary := req.Primary
companions := req.Companions
testNamesToIds := getTestNamesToIds(tests)
testNames := getTestNames(tests)
addr, err := device.Address(primary)
if err != nil {
return nil, fmt.Errorf("cannot get address from DUT: %v", primary)
}
var companionAddrs []string
for _, c := range companions {
address, err := device.Address(c)
if err != nil {
return nil, fmt.Errorf("cannot get address from companion device: %v", c)
}
companionAddrs = append(companionAddrs, address)
}
args := newTautoArgs(addr, companionAddrs, testNames, resultsDir)
// Run RTD.
cmd := exec.Command("/usr/bin/test_that", genTautoArgList(args)...)
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, fmt.Errorf("StderrPipe failed")
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("StdoutPipe failed")
}
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to run Tauto: %v", err)
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
td.logger.Printf("[tauto] %v", scanner.Text())
}
}()
go func() {
defer wg.Done()
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
td.logger.Printf("[tauto] %v", scanner.Text())
}
}()
wg.Wait()
if err := cmd.Wait(); err != nil {
return nil, fmt.Errorf("fail to run tauto: %s", err)
}
results, err := tautoresults.TestsReports(resultsDir, testNames, testNamesToIds)
if err != nil {
return &api.CrosTestResponse{}, err
}
return &api.CrosTestResponse{TestCaseResults: results}, nil
}
// Flag names. More to be populated once impl details are firmed.
const (
autotestDirFlag = "--autotest_dir"
tautoResultsDirFlag = "--results_dir"
companionFlag = "--companion_hosts"
)
// tautoRunArgs stores arguments to invoke tauto
type tautoRunArgs struct {
target string // The url for the target machine.
patterns []string // The names of test to be run.
runFlags map[string]string // The flags for tauto run command.
}
// newTautoArgs created an argument structure for invoking tauto
func newTautoArgs(dut string, companions, tests []string, resultsDir string) *tautoRunArgs {
args := tautoRunArgs{
target: dut,
runFlags: map[string]string{
autotestDirFlag: common.AutotestDir,
},
}
if len(companions) > 0 {
companionsAddresses := strings.Join(companions, ",")
args.runFlags[companionFlag] = companionsAddresses
}
args.patterns = tests // TO-DO Support Tags
args.runFlags[tautoResultsDirFlag] = resultsDir
return &args
}
// genArgList generates argument list for invoking Tauto
func genTautoArgList(args *tautoRunArgs) (argList []string) {
for flag, value := range args.runFlags {
argList = append(argList, fmt.Sprintf("%v=%v", flag, value))
}
argList = append(argList, args.target)
argList = append(argList, args.patterns...)
return argList
}