diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go index 0af7d3c5685..33e33328f9d 100644 --- a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "log" - "math" "net/http" "net/url" "strconv" @@ -906,53 +905,80 @@ func (in *infraService) GetVersionDetails() (*model.InfraVersionDetails, error) return &model.InfraVersionDetails{}, fmt.Errorf("failed to parse InfraCompatibleVersions config: %w", err) } - // To find the latest compatible version - compatibleMap := make(map[int]string) - - // To store the compatible versions in int format - var compatibleArrayInt []int + latestVersion := "" + for _, version := range compatibleArray { + if latestVersion == "" { + latestVersion = version + continue + } - for _, versionStr := range compatibleArray { - versionInt, err := updateVersionFormat(versionStr) + comparison, err := compareInfraVersions(version, latestVersion) if err != nil { return &model.InfraVersionDetails{}, err } - compatibleArrayInt = append(compatibleArrayInt, versionInt) - compatibleMap[versionInt] = versionStr + if comparison > 0 { + latestVersion = version + } } - // Fetching the latest version - latestVersion := fetchLatestVersion(compatibleMap) - return &model.InfraVersionDetails{LatestVersion: compatibleMap[latestVersion], CompatibleVersions: compatibleArray}, nil + return &model.InfraVersionDetails{LatestVersion: latestVersion, CompatibleVersions: compatibleArray}, nil } -// fetchLatestVersion returns the latest version available -func fetchLatestVersion(versions map[int]string) int { - var latestVersion int - for k := range versions { - if k > latestVersion { - latestVersion = k +func compareInfraVersions(version, otherVersion string) (int, error) { + if version == CIVersion && otherVersion == CIVersion { + return 0, nil + } + if version == CIVersion { + return -1, nil + } + if otherVersion == CIVersion { + return 1, nil + } + + parsedVersion, err := parseInfraVersion(version) + if err != nil { + return 0, err + } + + parsedOtherVersion, err := parseInfraVersion(otherVersion) + if err != nil { + return 0, err + } + + for i := range parsedVersion { + if parsedVersion[i] > parsedOtherVersion[i] { + return 1, nil + } + if parsedVersion[i] < parsedOtherVersion[i] { + return -1, nil } } - return latestVersion + + return 0, nil } -// updateVersionFormat converts string array to int by removing decimal points, 1.0.0 will be returned as 100, 0.1.0 will be returned as 10, 0.0.1 will be returned as 1 -func updateVersionFormat(str string) (int, error) { - if str == CIVersion { - return 0, nil +func parseInfraVersion(version string) ([3]int, error) { + version = strings.TrimSpace(version) + if version == CIVersion { + return [3]int{}, nil + } + + versionParts := strings.Split(version, ".") + if len(versionParts) != 3 { + return [3]int{}, fmt.Errorf("invalid infra version %q: expected major.minor.patch", version) } - var versionInt int - versionSlice := strings.Split(str, ".") - for i, val := range versionSlice { - x, err := strconv.Atoi(val) + + var parsedVersion [3]int + for i, part := range versionParts { + versionPart, err := strconv.Atoi(strings.TrimSpace(part)) if err != nil { - return -1, err + return [3]int{}, fmt.Errorf("invalid infra version %q: %w", version, err) } - versionInt += x * int(math.Pow(10, float64(2-i))) + parsedVersion[i] = versionPart } - return versionInt, nil + + return parsedVersion, nil } // QueryServerVersion is used to fetch the version of the server diff --git a/chaoscenter/graphql/server/pkg/chaos_infrastructure/service_test.go b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service_test.go new file mode 100644 index 00000000000..f25f180ab8c --- /dev/null +++ b/chaoscenter/graphql/server/pkg/chaos_infrastructure/service_test.go @@ -0,0 +1,64 @@ +package chaos_infrastructure + +import ( + "testing" + + "github.com/litmuschaos/litmus/chaoscenter/graphql/server/utils" +) + +func TestGetVersionDetailsSelectsLatestSemanticVersion(t *testing.T) { + previousCompatibleVersions := utils.Config.InfraCompatibleVersions + t.Cleanup(func() { + utils.Config.InfraCompatibleVersions = previousCompatibleVersions + }) + + utils.Config.InfraCompatibleVersions = `["3.29.0","4.0.0"]` + + service := NewChaosInfrastructureService(nil, nil, nil) + versionDetails, err := service.GetVersionDetails() + if err != nil { + t.Fatalf("GetVersionDetails returned error: %v", err) + } + + if versionDetails.LatestVersion != "4.0.0" { + t.Fatalf("expected latest version 4.0.0, got %q", versionDetails.LatestVersion) + } +} + +func TestGetVersionDetailsTreatsCIVersionAsLowestVersion(t *testing.T) { + previousCompatibleVersions := utils.Config.InfraCompatibleVersions + t.Cleanup(func() { + utils.Config.InfraCompatibleVersions = previousCompatibleVersions + }) + + utils.Config.InfraCompatibleVersions = `["ci","3.10.0"]` + + service := NewChaosInfrastructureService(nil, nil, nil) + versionDetails, err := service.GetVersionDetails() + if err != nil { + t.Fatalf("GetVersionDetails returned error: %v", err) + } + + if versionDetails.LatestVersion != "3.10.0" { + t.Fatalf("expected latest version 3.10.0, got %q", versionDetails.LatestVersion) + } +} + +func TestGetVersionDetailsTreatsCIVersionAsLowerThanZeroVersion(t *testing.T) { + previousCompatibleVersions := utils.Config.InfraCompatibleVersions + t.Cleanup(func() { + utils.Config.InfraCompatibleVersions = previousCompatibleVersions + }) + + utils.Config.InfraCompatibleVersions = `["ci","0.0.0"]` + + service := NewChaosInfrastructureService(nil, nil, nil) + versionDetails, err := service.GetVersionDetails() + if err != nil { + t.Fatalf("GetVersionDetails returned error: %v", err) + } + + if versionDetails.LatestVersion != "0.0.0" { + t.Fatalf("expected latest version 0.0.0, got %q", versionDetails.LatestVersion) + } +}