package modules import ( _ "embed" "fmt" "os" "sort" "strings" "git.frostfs.info/TrueCloudLab/s3-tests-parser/internal/parser" "git.frostfs.info/TrueCloudLab/s3-tests-parser/internal/s3" "git.frostfs.info/TrueCloudLab/s3-tests-parser/internal/templates" "github.com/spf13/cobra" "github.com/spf13/viper" ) var compatibilityCmd = &cobra.Command{ Use: "compatibility", Short: "Shows compatibility results", Long: "Form compatibility table based on passed s3 tests", Example: `s3-tests-parser compatibility suite.csv s3-tests-parser compatibility suite.json --format json s3-tests-parser compatibility suite.json --format json --output-format md s3-tests-parser compatibility suite.json --format json --output-format md --output result.md s3-tests-parser compatibility suite.json --format json --output-format txt --output result.txt --verbose s3-tests-parser compatibility suite.json --format json --output-format txt --output result.txt --verbose s3-tests-parser compatibility suite.json --format json --output-format txt --output result.txt --verbose --include-ignored `, RunE: runCompatibilityCmd, } type ( Results struct { Verbose bool Legend []Status TagGroups []TagGroup } TagGroup struct { Name string Tests []TestResult } Status struct { Color string Description string } TestResult struct { Color string Name string Comment string Passed int Total int FailedTests []string PassedTests []string } ) const ( formatFlag = "format" outputFlag = "output" outputFormatFlag = "output-format" verboseFlag = "verbose" allFlag = "all" ) func initCompatibilityCmd() { compatibilityCmd.Flags().String(formatFlag, "csv", "format of input test suite file") compatibilityCmd.Flags().String(outputFlag, "", "file to write output, if missed the stdout is used") compatibilityCmd.Flags().String(outputFormatFlag, "txt", "format of output") compatibilityCmd.Flags().Bool(verboseFlag, false, "produce additional info") compatibilityCmd.Flags().Bool(allFlag, false, "include in output ignored tests") } func runCompatibilityCmd(cmd *cobra.Command, args []string) error { if len(args) != 1 { return fmt.Errorf("expected exactly one arg, got: %v", args) } testStruct, err := s3.ParseTestsStruct() if err != nil { return err } testsMap, err := parser.ParseSuite(args[0], viper.GetString(formatFlag)) if err != nil { return fmt.Errorf("parse tests: %w", err) } res := formResults(testStruct, testsMap) res.Verbose = viper.GetBool(verboseFlag) if !viper.GetBool(allFlag) { for i, group := range res.TagGroups { if group.Name == "Ignored" { res.TagGroups = append(res.TagGroups[:i], res.TagGroups[i+1:]...) break } } } return printResults(cmd, res) } var legend = []Status{ { Color: templates.GreenColor, Description: "Supported", }, { Color: templates.YellowColor, Description: "Partially supported", }, { Color: templates.RedColor, Description: "Badly supported", }, { Color: templates.BlueColor, Description: "Not supported", }, { Color: templates.BlackColor, Description: "Not applicable or will never be supported", }, } func formResults(testStruct s3.TestsStructure, testsMap map[string]bool) Results { tagGroups := make(map[string]TagGroup) groupTests := make(map[string][]string) for _, group := range testStruct.Groups { groupTests[group.Name] = group.Tests } for _, group := range testStruct.Groups { tagGroup, ok := tagGroups[group.Tag] if !ok { tagGroup.Name = group.Tag } for _, n := range group.Include { group.Tests = append(group.Tests, groupTests[n]...) } tagGroup.Tests = append(tagGroup.Tests, formTestResult(group, testsMap)) tagGroups[group.Tag] = tagGroup } res := Results{Legend: legend} for _, group := range tagGroups { res.TagGroups = append(res.TagGroups, group) } sort.Slice(res.TagGroups, func(i, j int) bool { return res.TagGroups[i].Name < res.TagGroups[j].Name }) return res } func formTestResult(group s3.Group, testsMap map[string]bool) TestResult { ln := len(group.Tests) var failed []string var passed []string for _, test := range group.Tests { split := strings.Split(test, "::") // to trim test path if len(split) != 2 { continue } testName := split[1] if testsMap[testName] { passed = append(passed, testName) } else { failed = append(failed, testName) } } var color string if strings.Contains(group.Comment, "Not supported") { color = templates.BlueColor } else if strings.Contains(group.Comment, "Not applicable") { color = templates.BlackColor } else if ln == 0 && !group.Skip { color = templates.GreenColor } if color == "" { color = templates.RedColor rate := float64(len(passed)) / float64(ln) if rate > 0.9 { color = templates.GreenColor } else if rate > 0.5 { color = templates.YellowColor } } return TestResult{ Color: color, Name: group.Name, Comment: group.Comment, Passed: len(passed), Total: ln, FailedTests: failed, PassedTests: passed, } } func printResults(cmd *cobra.Command, res Results) error { w := cmd.OutOrStdout() if outFile := viper.GetString(outputFlag); outFile != "" { f, err := os.Create(outFile) if err != nil { return fmt.Errorf("create out file: %w", err) } w = f defer f.Close() } outTemplate, err := templates.GetTemplate(viper.GetString(outputFormatFlag)) if err != nil { return fmt.Errorf("form out template: %w", err) } return outTemplate.Execute(w, res) }