crowdsec/cmd/crowdsec-cli/clihubtest/coverage.go
mmetc cab99643d1
Parallel hubtest (#3509)
Hubtests are now much faster and have a --max-jobs option which defaults to the number of cpu cores.
2025-03-17 11:27:09 +01:00

168 lines
4.2 KiB
Go

package clihubtest
import (
"encoding/json"
"errors"
"fmt"
"math"
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/crowdsecurity/crowdsec/cmd/crowdsec-cli/args"
"github.com/crowdsecurity/crowdsec/pkg/hubtest"
)
// getCoverage returns the coverage and the percentage of tests that passed
func getCoverage(show bool, getCoverageFunc func(string) ([]hubtest.Coverage, error), hubDir string) ([]hubtest.Coverage, int, error) {
if !show {
return nil, 0, nil
}
coverage, err := getCoverageFunc(hubDir)
if err != nil {
return nil, 0, fmt.Errorf("while getting coverage: %w", err)
}
tested := 0
for _, test := range coverage {
if test.TestsCount > 0 {
tested++
}
}
// keep coverage 0 if there's no tests?
percent := 0
if len(coverage) > 0 {
percent = int(math.Round((float64(tested) / float64(len(coverage)) * 100)))
}
return coverage, percent, nil
}
func (cli *cliHubTest) coverage(showScenarioCov bool, showParserCov bool, showAppsecCov bool, showOnlyPercent bool) error {
cfg := cli.cfg()
// for this one we explicitly don't do for appsec
if err := HubTest.LoadAllTests(); err != nil {
return fmt.Errorf("unable to load all tests: %w", err)
}
var err error
// if all are false (flag by default), show them
if !showParserCov && !showScenarioCov && !showAppsecCov {
showParserCov = true
showScenarioCov = true
showAppsecCov = true
}
parserCoverage, parserCoveragePercent, err := getCoverage(showParserCov, HubTest.GetParsersCoverage, cfg.Hub.HubDir)
if err != nil {
return err
}
scenarioCoverage, scenarioCoveragePercent, err := getCoverage(showScenarioCov, HubTest.GetScenariosCoverage, cfg.Hub.HubDir)
if err != nil {
return err
}
appsecRuleCoverage, appsecRuleCoveragePercent, err := getCoverage(showAppsecCov, HubTest.GetAppsecCoverage, cfg.Hub.HubDir)
if err != nil {
return err
}
if showOnlyPercent {
switch {
case showParserCov:
fmt.Printf("parsers=%d%%", parserCoveragePercent)
case showScenarioCov:
fmt.Printf("scenarios=%d%%", scenarioCoveragePercent)
case showAppsecCov:
fmt.Printf("appsec_rules=%d%%", appsecRuleCoveragePercent)
}
return nil
}
switch cfg.Cscli.Output {
case "human":
if showParserCov {
hubTestCoverageTable(color.Output, cfg.Cscli.Color, []string{"Parser", "Status", "Number of tests"}, parserCoverage)
}
if showScenarioCov {
hubTestCoverageTable(color.Output, cfg.Cscli.Color, []string{"Scenario", "Status", "Number of tests"}, parserCoverage)
}
if showAppsecCov {
hubTestCoverageTable(color.Output, cfg.Cscli.Color, []string{"Appsec Rule", "Status", "Number of tests"}, parserCoverage)
}
fmt.Println()
if showParserCov {
fmt.Printf("PARSERS : %d%% of coverage\n", parserCoveragePercent)
}
if showScenarioCov {
fmt.Printf("SCENARIOS : %d%% of coverage\n", scenarioCoveragePercent)
}
if showAppsecCov {
fmt.Printf("APPSEC RULES : %d%% of coverage\n", appsecRuleCoveragePercent)
}
case "json":
dump, err := json.MarshalIndent(parserCoverage, "", " ")
if err != nil {
return err
}
fmt.Printf("%s", dump)
dump, err = json.MarshalIndent(scenarioCoverage, "", " ")
if err != nil {
return err
}
fmt.Printf("%s", dump)
dump, err = json.MarshalIndent(appsecRuleCoverage, "", " ")
if err != nil {
return err
}
fmt.Printf("%s", dump)
default:
return errors.New("only human/json output modes are supported")
}
return nil
}
func (cli *cliHubTest) newCoverageCmd() *cobra.Command {
var (
showParserCov bool
showScenarioCov bool
showOnlyPercent bool
showAppsecCov bool
)
cmd := &cobra.Command{
Use: "coverage",
Short: "coverage",
Args: args.NoArgs,
DisableAutoGenTag: true,
RunE: func(_ *cobra.Command, _ []string) error {
return cli.coverage(showScenarioCov, showParserCov, showAppsecCov, showOnlyPercent)
},
}
cmd.PersistentFlags().BoolVar(&showOnlyPercent, "percent", false, "Show only percentages of coverage")
cmd.PersistentFlags().BoolVar(&showParserCov, "parsers", false, "Show only parsers coverage")
cmd.PersistentFlags().BoolVar(&showScenarioCov, "scenarios", false, "Show only scenarios coverage")
cmd.PersistentFlags().BoolVar(&showAppsecCov, "appsec", false, "Show only appsec coverage")
return cmd
}