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`, 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" ) 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") } 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) 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) }