blob: 9c8e7f0d93bc4b35b891239da2c2010f6dfb4ec3 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package planner
import (
"context"
"go.chromium.org/tast/core/internal/minidriver"
"go.chromium.org/tast/core/internal/minidriver/failfast"
"go.chromium.org/tast/core/internal/minidriver/target"
"go.chromium.org/tast/core/internal/planner/internal/fixture"
"go.chromium.org/tast/core/internal/planner/internal/output"
"go.chromium.org/tast/core/internal/protocol"
"go.chromium.org/tast/core/internal/testing"
frameworkprotocol "go.chromium.org/tast/core/framework/protocol"
)
// ExternalTarget specifies the external target bundle to run.
type ExternalTarget struct {
Device *protocol.TargetDevice
Config *protocol.RunTargetConfig
Bundle string
}
// runExternalTests runs tests in primary target.
// It sends a request to run the tests to the target bundle, and handles fixture
// stack operation requests.
// It returns an error If a test could not be run, or an internal framework
// error has happened.
// It returns unstarted tests.
// External tests might not fully finish in case Stack Reset failure.
// unstarted tests are returned for allowing retry unstarted tests.
func runExternalTests(ctx context.Context, names []string, stack *fixture.CombinedStack, pcfg *Config, out output.Stream) (unstarted []string, err error) {
scfg := &target.ServiceConfig{
Devservers: pcfg.ExternalTarget.Config.GetDevservers(),
TLWServer: pcfg.Service.GetTlwServer(),
UseEphemeralDevserver: pcfg.Service.GetUseEphemeralDevservers(),
TastDir: pcfg.Service.GetTastDir(),
ExtraAllowedBuckets: pcfg.Service.GetExtraAllowedBuckets(),
DebuggerPorts: []int{int(pcfg.ExternalTarget.Config.GetDebugPort())},
}
tcfg := &target.Config{
SSHConfig: pcfg.ExternalTarget.Device.GetDutConfig().GetSshConfig(),
TastVars: pcfg.Features.GetInfra().GetVars(),
ServiceConfig: scfg,
}
cc, err := target.NewConnCache(ctx, tcfg, pcfg.ExternalTarget.Device.GetDutConfig().GetSshConfig().GetConnectionSpec(), pcfg.ExternalTarget.Device.GetDutConfig().GetSshConfig().GetProxyCommand(), "")
if err != nil {
return nil, err
}
fixtureServer := fixture.NewStackServer(&fixture.StackServerConfig{
Out: out,
Stack: stack,
OutDir: pcfg.Dirs.GetOutDir(),
CloudStorage: testing.NewCloudStorage(
pcfg.Service.GetDevservers(),
pcfg.Service.GetTlwServer(),
pcfg.Service.GetTlwSelfName(),
pcfg.Service.GetDutServer(),
pcfg.DataFile.GetBuildArtifactsUrl(),
pcfg.Service.GetSwarmingTaskID(),
pcfg.Service.GetBuildBucketID(),
),
RemoteData: pcfg.RemoteData,
})
counter := failfast.NewCounter(int(pcfg.ExternalTarget.Config.GetMaxTestFailures()))
factory := minidriver.NewIntermediateHandlersFactory(pcfg.Dirs.GetOutDir(), counter, out.ExternalEvent, fixtureServer.Handle)
companionFeatures := make(map[string]*frameworkprotocol.DUTFeatures)
companionFeatures[""] = pcfg.Features.GetDut()
for key, value := range pcfg.Features.GetCompanionFeatures() {
companionFeatures[key] = value
}
cfg := &minidriver.Config{
Retries: int(pcfg.ExternalTarget.Config.GetRetries()),
ResDir: pcfg.Dirs.GetOutDir(),
Devservers: pcfg.ExternalTarget.Config.GetDevservers(),
Target: pcfg.ExternalTarget.Device.GetDutConfig().GetSshConfig().GetConnectionSpec(),
LocalDataDir: pcfg.ExternalTarget.Config.GetDirs().GetDataDir(),
LocalOutDir: pcfg.ExternalTarget.Config.GetDirs().GetOutDir(),
LocalTempDir: pcfg.ExternalTarget.Config.GetDirs().GetTempDir(),
LocalBundleDir: pcfg.ExternalTarget.Device.GetBundleDir(),
DownloadMode: pcfg.DataFile.GetDownloadMode(),
SwarmingTaskID: pcfg.ExternalTarget.Config.GetSwarmingTaskID(),
BuildBucketID: pcfg.ExternalTarget.Config.GetBuildBucketID(),
WaitUntilReady: pcfg.ExternalTarget.Config.GetWaitUntilReady(),
CheckTestDeps: pcfg.Features.GetCheckDeps(),
TestVars: pcfg.Features.GetInfra().GetVars(),
MaybeMissingVars: pcfg.Features.GetInfra().GetMaybeMissingVars(),
DUTLabConfig: pcfg.Features.GetInfra().GetDUTLabConfig(),
MsgTimeout: pcfg.ExternalTarget.Config.GetMsgTimeout().AsDuration(),
SystemServicesTimeout: pcfg.ExternalTarget.Config.GetSystemServicesTimeout().AsDuration(),
WaitUntilReadyTimeout: pcfg.ExternalTarget.Config.GetWaitUntilReadyTimeout().AsDuration(),
DebuggerPort: int(pcfg.ExternalTarget.Config.GetDebugPort()),
Proxy: pcfg.ExternalTarget.Config.GetProxy(),
DUTFeatures: companionFeatures,
ForceSkips: pcfg.Features.ForceSkips,
Factory: factory,
BuildArtifactsURL: pcfg.DataFile.GetBuildArtifactsUrl(),
Recursive: true,
}
d := minidriver.NewDriver(cfg, cc)
startFixture := stack.Top()
jsonResults, err := d.RunLocalTests(ctx, pcfg.ExternalTarget.Bundle, names, startFixture)
if err == minidriver.ErrNoTestRanInLastAttempt {
if len(jsonResults) == 0 {
return nil, err
}
// Fixture failure stopped local tests running.
} else if err != nil {
return nil, err
}
startedSet := make(map[string]struct{})
for _, t := range jsonResults {
startedSet[t.Name] = struct{}{}
}
for _, name := range names {
if _, ok := startedSet[name]; !ok {
unstarted = append(unstarted, name)
}
}
return unstarted, nil
}