blob: 1c29570c130b21132e5c69b129a1b67a9305b3f8 [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.
// Provides service implementations and management
package services
import (
"fmt"
"os/exec"
"go.chromium.org/chromiumos/config/go/test/api"
"go.chromium.org/chromiumos/test/local-cft/internal/utils"
)
type crosTestFinderServiceCommands struct {
FindTests ServiceCommand_
}
// Enum of available commands for cros-test-finder
func CROS_TEST_FINDER_SERVICE_COMMANDS() crosTestFinderServiceCommands {
return crosTestFinderServiceCommands{
FindTests: "find-tests",
}
}
// Service implementation for cros-test-finder
type CrosTestFinderService struct {
Service
ServiceBase
client api.TestFinderServiceClient
}
func (c *CrosTestFinderService) Start() error {
c.EnsurePort()
c.LocalLogger.Printf("Starting %s on port %d", c.Name, c.Port)
starter := &SetupCrosTestFinder{
ctf: c,
}
return c.executor.Start(starter)
}
func (c *CrosTestFinderService) Execute(commandName ServiceCommand_, args ...interface{}) error {
var cmd ServiceCommand = nil
switch commandName {
case CROS_TEST_FINDER_SERVICE_COMMANDS().FindTests:
cmd = &FindTestsCommand{
ctf: c,
}
default:
return fmt.Errorf("Command %s not found", commandName)
}
return c.executor.Execute(cmd)
}
func (c *CrosTestFinderService) Stop() error {
stopper := &StopCrosTestFinder{
ctf: c,
}
return c.executor.Stop(stopper)
}
// Setup
type SetupCrosTestFinder struct {
ServiceSetup
ctf *CrosTestFinderService
}
func (starter *SetupCrosTestFinder) Setup() error {
if err := utils.EnsureContainerAvailable(starter.ctf.Name); err != nil {
err := fmt.Errorf("Failed to ensure container %s was available, %s", starter.ctf.Name, err)
starter.ctf.LocalLogger.Println(err)
return err
}
containerImage := fmt.Sprintf(
"us-docker.pkg.dev/cros-registry/test-services/%s:%s",
starter.ctf.Name,
starter.ctf.manager.images[starter.ctf.Name].Tags[0],
)
if _, ok := starter.ctf.manager.LocalServices[starter.ctf.Name]; ok {
err := utils.UpdateContainerService(starter.ctf.LocalLogger, starter.ctf.manager.Chroot, containerImage, starter.ctf.Name)
if err != nil {
starter.ctf.LocalLogger.Println(err)
return err
}
containerImage = containerImage + "_localchange"
}
request := &api.StartContainerRequest{
Name: starter.ctf.Name,
ContainerImage: containerImage,
AdditionalOptions: &api.StartContainerRequest_Options{
Expose: []string{fmt.Sprint(starter.ctf.Port)},
Network: "host",
},
StartCommand: []string{
"cros-test-finder",
"server",
"-port",
fmt.Sprint(starter.ctf.Port),
},
}
starter.ctf.manager.Execute(
SERVICES().CrosToolRunner,
CTR_SERVICE_COMMANDS().StartContainer,
request,
)
go BuildServiceListener(
&starter.ctf.ServiceBase,
false,
exec.Command("docker", "logs", "-f", starter.ctf.Name),
)()
if err := <-starter.ctf.ReadyChan; err != nil {
starter.ctf.LocalLogger.Println(err)
return err
}
if err := BuildConnection(&starter.ctf.ServiceBase); err != nil {
return err
}
starter.ctf.client = api.NewTestFinderServiceClient(starter.ctf.conn)
return nil
}
// Stopper
type StopCrosTestFinder struct {
ServiceStopper
ctf *CrosTestFinderService
}
func (stopper *StopCrosTestFinder) Stop() error {
if stopper.ctf.conn != nil {
stopper.ctf.conn.Close()
}
if stopper.ctf.Started {
stopper.ctf.CloseChan <- struct{}{}
<-stopper.ctf.CloseFinishedChan
}
WriteLogs(&stopper.ctf.ServiceBase)
return nil
}
// Commands
type FindTestsCommand struct {
ServiceCommand
ctf *CrosTestFinderService
}
func (cmd *FindTestsCommand) Execute() error {
testSuites := []*api.TestSuite{}
var tags []string = nil
var tagsExclude []string = nil
if len(cmd.ctf.manager.Tags) > 0 && cmd.ctf.manager.Tags[0] != "" {
tags = cmd.ctf.manager.Tags
}
if len(cmd.ctf.manager.TagsExclude) > 0 && cmd.ctf.manager.TagsExclude[0] != "" {
tagsExclude = cmd.ctf.manager.TagsExclude
}
if tags != nil || tagsExclude != nil {
testSuites = append(testSuites, &api.TestSuite{
Spec: &api.TestSuite_TestCaseTagCriteria_{
TestCaseTagCriteria: &api.TestSuite_TestCaseTagCriteria{
Tags: tags,
TagExcludes: tagsExclude,
},
},
})
}
testCaseIds := []*api.TestCase_Id{}
for _, testCaseId := range cmd.ctf.manager.Tests {
if testCaseId != "" {
testCaseIds = append(testCaseIds, &api.TestCase_Id{
Value: testCaseId,
})
}
}
if len(testCaseIds) > 0 {
testSuites = append(testSuites, &api.TestSuite{
Spec: &api.TestSuite_TestCaseIds{
TestCaseIds: &api.TestCaseIdList{
TestCaseIds: testCaseIds,
},
},
})
}
findTestsRequest := &api.CrosTestFinderRequest{
TestSuites: testSuites,
}
findTestResult, err := cmd.ctf.client.FindTests(cmd.ctf.manager.ctx, findTestsRequest)
if err != nil {
return fmt.Errorf("Failed to find tests, %s", err)
}
cmd.ctf.manager.testSuites = []*api.TestSuite{}
for _, testSuite := range findTestResult.TestSuites {
cmd.ctf.LocalLogger.Printf("Found %d tests:\n", len(testSuite.GetTestCases().TestCases))
cmd.ctf.LocalLogger.Printf("%v\n", testSuite.GetTestCases().TestCases)
testCaseIds := []*api.TestCase_Id{}
for _, testCase := range testSuite.GetTestCases().TestCases {
testCaseIds = append(testCaseIds, testCase.Id)
}
cmd.ctf.manager.testSuites = append(cmd.ctf.manager.testSuites, &api.TestSuite{
Spec: &api.TestSuite_TestCaseIds{
TestCaseIds: &api.TestCaseIdList{
TestCaseIds: testCaseIds,
},
},
})
}
return nil
}