blob: 33b10ff46c8cea7a945063c38c5ebb79eb5be329 [file] [log] [blame]
package main
import (
"encoding/json"
"os"
"github.com/spf13/cobra"
"go.skia.org/infra/gold-client/go/goldclient"
"go.skia.org/infra/golden/go/jsonio"
"go.skia.org/infra/golden/go/shared"
)
// imgTestEnv is the environment for the imgtest command ant its sub-commands.
type imgTestEnv struct {
// Flags used by imgtest:init and imgtest:add.
flagCommit string // flag containing the commit hash
flagKeysFile string
flagIssueID string
flagPatchsetID string
flagJobID string
flagInstanceID string
flagWorkDir string
flagPassFailStep bool
flagFailureFile string
flagURL string
// Flags used by imgtest:add
flagTestName string
flagPNGFile string
}
// getImgTestCmd returns the definition of the imgtest command.
func getImgTestCmd() *cobra.Command {
env := &imgTestEnv{}
// imgtest command and its sub commands
imgTestCmd := &cobra.Command{
Use: "imgtest",
Short: "Collect and upload test results as images",
Long: `
Collect and upload test results to the Gold backend.`,
}
// cmd: imgtest init
imgTestInitCmd := &cobra.Command{
Use: "init",
Short: "Initialize a testing environment",
Long: `
Start a testing session during which tests are added. This initializes the environment.
It gathers whether the 'add' command returns a pass/fail value and the common
keys shared by all tests that are added via 'add'.`,
Run: env.runImgTestInitCmd,
}
env.addCommonFlags(imgTestInitCmd, false)
imgTestAddCmd := &cobra.Command{
Use: "add",
Short: "Adds a test image to the results.",
Long: `
Add images generated by the tests to the test results. This requires two arguments:
- The test name
- The path to the resulting PNG.
`,
Run: env.runImgTestAddCmd,
Args: cobra.NoArgs,
}
env.addCommonFlags(imgTestAddCmd, false)
imgTestAddCmd.Flags().StringVarP(&env.flagTestName, "test-name", "", "", "Unique name of the test, must not contain spaces.")
imgTestAddCmd.Flags().StringVarP(&env.flagPNGFile, "png-file", "", "", "Path to the PNG file that contains the test results.")
imgTestFinalizeCmd := &cobra.Command{
Use: "finalize",
Short: "Finish adding tests and process results.",
Long: `
All tests have been added. Upload images and generate and upload the JSON file that captures
test results.`,
Run: env.runImgTestFinalizeCmd,
}
imgTestPassFailCmd := &cobra.Command{
Use: "passfail",
Short: "Checks whether the results match expectations",
Long: `
Check against Gold or local baseline whether the results match the expectations`,
Run: env.runImgTestPassFailCmd,
}
// assemble the imgtest command.
imgTestCmd.AddCommand(
imgTestInitCmd,
imgTestAddCmd,
imgTestFinalizeCmd,
imgTestPassFailCmd,
)
return imgTestCmd
}
func (i *imgTestEnv) addCommonFlags(cmd *cobra.Command, optional bool) {
cmd.Flags().StringVarP(&i.flagInstanceID, "instance", "", "", "ID of the Gold instance.")
cmd.Flags().StringVarP(&i.flagWorkDir, fstrWorkDir, "", "", "Temporary work directory")
cmd.Flags().BoolVarP(&i.flagPassFailStep, "passfail", "", false, "Whether the 'add' call returns a pass/fail for each test.")
cmd.Flags().StringVarP(&i.flagCommit, "commit", "", "", "Git commit hash")
cmd.Flags().StringVarP(&i.flagKeysFile, "keys-file", "", "", "JSON file containing key/value pairs commmon to all tests")
cmd.Flags().StringVarP(&i.flagIssueID, "issue", "", "", "Gerrit issue if this is trybot run. ")
cmd.Flags().StringVarP(&i.flagPatchsetID, "patchset", "", "", "Gerrit patchset number if this is a trybot run. ")
cmd.Flags().StringVarP(&i.flagJobID, "jobid", "", "", "Job ID if this is a tryjob run. Current the BuildBucket id.")
cmd.Flags().StringVarP(&i.flagFailureFile, "failure-file", "", "", "Path to the file where to write failure information")
cmd.Flags().StringVarP(&i.flagURL, "url", "", "", "URL of the Gold instance. Used for testing, if empty the URL will be derived from the value of 'instance'")
if !optional {
_ = cmd.MarkFlagRequired("instance")
_ = cmd.MarkFlagRequired(fstrWorkDir)
_ = cmd.MarkFlagRequired("passfail")
_ = cmd.MarkFlagRequired("commit")
_ = cmd.MarkFlagRequired("keys-file")
}
}
// TODO(stephana): Implement these stubbed out sub-commands.
func (i *imgTestEnv) runImgTestInitCmd(cmd *cobra.Command, args []string) { notImplemented(cmd) }
func (i *imgTestEnv) runImgTestFinalizeCmd(cmd *cobra.Command, args []string) { notImplemented(cmd) }
func (i *imgTestEnv) runImgTestPassFailCmd(cmd *cobra.Command, args []string) { notImplemented(cmd) }
// runImgTestCommand processes and uploads test results to Gold.
func (i *imgTestEnv) runImgTestAddCmd(cmd *cobra.Command, args []string) {
keyMap, err := readKeysFile(i.flagKeysFile)
ifErrLogExit(cmd, err)
validation := shared.Validation{}
issueID := validation.Int64Value("issue", i.flagIssueID, 0)
patchsetID := validation.Int64Value("patchset", i.flagPatchsetID, 0)
jobID := validation.Int64Value("jobid", i.flagJobID, 0)
ifErrLogExit(cmd, validation.Errors())
// Define the meta data of the result that is shared by all tests.
gr := &jsonio.GoldResults{
GitHash: i.flagCommit,
Key: keyMap,
Issue: issueID,
Patchset: patchsetID,
BuildBucketID: jobID,
}
config := &goldclient.GoldClientConfig{
InstanceID: i.flagInstanceID,
WorkDir: i.flagWorkDir,
PassFailStep: i.flagPassFailStep,
OverrideGoldURL: i.flagURL,
}
goldClient, err := goldclient.NewCloudClient(config, gr)
ifErrLogExit(cmd, err)
pass, err := goldClient.Test(i.flagTestName, i.flagPNGFile)
ifErrLogExit(cmd, err)
if !pass {
logErrf(cmd, "Test: %s FAIL\n", i.flagTestName)
os.Exit(1)
}
logInfof(cmd, "Test: %s PASS\n", i.flagTestName)
os.Exit(0)
}
// readKeysFile is a helper function to read a JSON file with key/value pairs.
func readKeysFile(keysFile string) (map[string]string, error) {
reader, err := os.Open(keysFile)
if err != nil {
return nil, err
}
ret := map[string]string{}
err = json.NewDecoder(reader).Decode(&ret)
return ret, err
}