blob: 25077161200f111fedc033c8715feced33d615eb [file]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
server "chromiumos/test/ctpv2/common/server_template"
"context"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"github.com/golang/protobuf/jsonpb"
"go.chromium.org/chromiumos/config/go/test/api"
)
const (
address = "localhost"
binName = "test_finder_filter"
testFinderDir = "/tmp/test-finder"
)
func toCTPTestCase(metadata *api.TestCaseMetadata) *api.CTPTestCase {
return &api.CTPTestCase{
Name: metadata.GetTestCase().GetName(),
Metadata: metadata,
}
}
func toTestFinderRequest(testPlan *api.InternalTestplan) (*api.CrosTestFinderRequest, error) {
// TODO... switch
testSuite, ok := testPlan.GetSuiteInfo().GetSuiteRequest().GetSuiteRequest().(*api.SuiteRequest_TestSuite)
if !ok {
return nil, errors.New("SuiteRequest is not TestSuite")
}
return &api.CrosTestFinderRequest{
TestSuites: []*api.TestSuite{testSuite.TestSuite},
MetadataRequired: true,
}, nil
}
// fillTestCases will make cros-test-finder request from SuiteInfo.SuiteRequest,
// and fill in the TestCases field with test cases information from the response.
func fillTestCases(ctx context.Context, testPlan *api.InternalTestplan, resp *api.CrosTestFinderResponse, log *log.Logger) error {
// TODO loop through testSuites.
if len(resp.GetTestSuites()) == 0 {
return nil
}
metadataList, ok := resp.GetTestSuites()[0].Spec.(*api.TestSuite_TestCasesMetadata)
if !ok {
return errors.New("no test cases metadata in the response")
}
log.Println("Going to translate...")
for _, metadata := range metadataList.TestCasesMetadata.GetValues() {
log.Println(metadata)
testPlan.TestCases = append(testPlan.TestCases, toCTPTestCase(metadata))
}
return nil
}
func executor(req *api.InternalTestplan, log *log.Logger) (*api.InternalTestplan, error) {
ctx := context.Background()
testFinderResponse, err := startAndRunTestFinder(req, log)
if err != nil {
log.Println("Error with TestFinder: ", err)
return req, err
}
log.Println("Called TestFinder successfully:", fmt.Sprintf("%s", testFinderResponse))
err = fillTestCases(ctx, req, testFinderResponse, log)
if err != nil {
log.Println("Error with setting internalPlan: ", err)
return req, err
}
return req, nil
}
func startAndRunTestFinder(testPlan *api.InternalTestplan, log *log.Logger) (*api.CrosTestFinderResponse, error) {
input := fmt.Sprintf("%s/test-finder-request.json", testFinderDir)
output := fmt.Sprintf("%s/test-finder-response.json", testFinderDir)
err := os.Mkdir(testFinderDir, 0777)
if err != nil {
log.Fatal(err)
}
req, err := toTestFinderRequest(testPlan)
if err != nil {
return nil, fmt.Errorf("Failed to Translate Request: %s", err)
}
log.Printf("made req: %s", req)
err = writeTestFinderInput(input, req)
if err != nil {
return nil, fmt.Errorf("Failed to write test-finder request to file API: %s", err)
}
err = callTestFinderr(input, output, log)
if err != nil {
return nil, fmt.Errorf("Failed2 to call test-finder: %s", err)
}
response, err := unMarshalResponse(output, log)
log.Printf("Got Response: %s", response)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal response: %s", err)
}
return response, nil
}
// unMarshalResponse reads/unmarshals output file generated by cros-test-finder.
func unMarshalResponse(filePath string, log *log.Logger) (*api.CrosTestFinderResponse, error) {
r, err := os.Open(filePath)
if err != nil {
log.Println("Test-Finder Filter unable to open test-finder response: ", err)
return nil, fmt.Errorf("unable to open file: %s", err)
}
out := &api.CrosTestFinderResponse{}
umrsh := jsonpb.Unmarshaler{AllowUnknownFields: true}
err = umrsh.Unmarshal(r, out)
if err != nil {
log.Println("Test-Finder Filter unable to marshal test-finder response: ", err)
return nil, fmt.Errorf("unable to marshal response: %s", err)
}
return out, nil
}
func getLog() string {
fileContents, _ := ioutil.ReadFile(fmt.Sprintf("%s/log.txt", testFinderDir))
return string(fileContents)
}
func callTestFinderr(input string, response string, log *log.Logger) error {
args := []string{"cli", "-input", input, "-output", response, "-log", testFinderDir}
cmd := exec.Command("cros-test-finder", args...)
err := cmd.Run()
logString := getLog()
log.Println("TestFinder String:")
log.Println(logString)
if err != nil {
return fmt.Errorf("unable to run test-finder: %s", err)
}
return nil
}
// writeTestFinderInput writes a CrosTestFinderRequest json.
func writeTestFinderInput(file string, req *api.CrosTestFinderRequest) error {
f, err := os.Create(file)
if err != nil {
return fmt.Errorf("fail to create file: %s", err)
}
m := jsonpb.Marshaler{}
if err := m.Marshal(f, req); err != nil {
return fmt.Errorf("fail to marshal request file: %s", err)
}
return nil
}
func main() {
err := server.Server(executor, binName)
if err != nil {
os.Exit(2)
}
os.Exit(0)
}