plugins/reporters/targetsuccess/targetsuccess.go (95 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. package targetsuccess import ( "encoding/json" "fmt" "github.com/facebookincubator/contest/pkg/event/testevent" "github.com/facebookincubator/contest/pkg/job" "github.com/facebookincubator/contest/pkg/lib/comparison" "github.com/facebookincubator/contest/pkg/xcontext" ) // Name defines the name of the reporter used within the plugin registry var Name = "TargetSuccess" // RunParameters contains the parameters necessary for the run reporter to // elaborate the results of the Job type RunParameters struct { SuccessExpression string } // FinalParameters contains the parameters necessary for the final reporter to // elaborate the results of the Job type FinalParameters struct { AverageSuccessExpression string } // TargetSuccessReporter implements a reporter which determines whether the Job has been // successful or not based on the number of Targets which succeeded/failed during // the various Test runs type TargetSuccessReporter struct { } // TargetSuccessReport wraps a report with target success information. type TargetSuccessReport struct { Message string AchievedSuccess string DesiredSuccess string } // ValidateRunParameters validates the parameters for the run reporter func (ts *TargetSuccessReporter) ValidateRunParameters(params []byte) (interface{}, error) { var rp RunParameters if err := json.Unmarshal(params, &rp); err != nil { return nil, err } if _, err := comparison.ParseExpression(rp.SuccessExpression); err != nil { return nil, fmt.Errorf("could not parse success expression") } return rp, nil } // ValidateFinalParameters validates the parameters for the final reporter func (ts *TargetSuccessReporter) ValidateFinalParameters(params []byte) (interface{}, error) { var fp FinalParameters if err := json.Unmarshal(params, &fp); err != nil { return nil, err } if _, err := comparison.ParseExpression(fp.AverageSuccessExpression); err != nil { return nil, fmt.Errorf("could not parse average success expression") } return fp, nil } // Name returns the Name of the reporter func (ts *TargetSuccessReporter) Name() string { return Name } // RunReport calculates the report to be associated with a job run. func (ts *TargetSuccessReporter) RunReport(ctx xcontext.Context, parameters interface{}, runStatus *job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { var ( success, fail uint64 testReports []string ) runSuccess := true reportParameters, ok := parameters.(RunParameters) if !ok { return false, nil, fmt.Errorf("report parameters should be of type TargetSuccessParameters") } // Flag the run as successful only if all Tests within the Run where successful for _, t := range runStatus.TestStatuses { fail = 0 success = 0 for _, t := range t.TargetStatuses { if t.Error != "" { fail++ } else { success++ } } if success+fail == 0 { return false, nil, fmt.Errorf("overall count of success and failures is zero for test %s", t.TestCoordinates.TestName) } cmpExpr, err := comparison.ParseExpression(reportParameters.SuccessExpression) if err != nil { return false, nil, fmt.Errorf("error while calculating run report for test %s: %v", t.TestCoordinates.TestName, err) } res, err := cmpExpr.EvaluateSuccess(success, success+fail) if err != nil { return false, nil, fmt.Errorf("error while calculating run report for test %s: %v", t.TestCoordinates.TestName, err) } if !res.Pass { testReports = append(testReports, fmt.Sprintf("Test %s does not pass success criteria: %s", t.TestCoordinates.TestName, res.Expr)) runSuccess = false } else { testReports = append(testReports, fmt.Sprintf("Test %s passes success criteria: %s", t.TestCoordinates.TestName, res.Expr)) } } return runSuccess, testReports, nil } // FinalReport calculates the final report to be associated to a job. func (ts *TargetSuccessReporter) FinalReport(ctx xcontext.Context, parameters interface{}, runStatuses []job.RunStatus, ev testevent.Fetcher) (bool, interface{}, error) { return false, nil, fmt.Errorf("final reporting not implemented yet in %s", Name) } // New builds a new TargetSuccessReporter func New() job.Reporter { return &TargetSuccessReporter{} } // Load returns the name and factory which are needed to register the Reporter func Load() (string, job.ReporterFactory) { return Name, New }