diff --git a/go.mod b/go.mod index 7f82f1c2..1f67565b 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( golang.org/x/mod v0.20.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 + gotest.tools v1.4.0 ) require ( @@ -32,6 +33,8 @@ require ( github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/gotestyourself/gotestyourself v1.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect diff --git a/go.sum b/go.sum index 86dad9c1..1bc0a53e 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gotestyourself/gotestyourself v1.4.0 h1:CDSlSIuRL/Fsc72Ln5lMybtrCvSRDddsHsDRG/nP7Rg= +github.com/gotestyourself/gotestyourself v1.4.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -196,3 +198,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v1.4.0 h1:BjtEgfuw8Qyd+jPvQz8CfoxiO/UjFEidWinwEXZiWv0= +gotest.tools v1.4.0/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/pkg/apis/enricher/framework/java/openliberty_detector.go b/pkg/apis/enricher/framework/java/openliberty_detector.go index b09cfb1c..c49dffd1 100644 --- a/pkg/apis/enricher/framework/java/openliberty_detector.go +++ b/pkg/apis/enricher/framework/java/openliberty_detector.go @@ -14,6 +14,7 @@ package enricher import ( "context" "encoding/xml" + "strings" "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/utils" @@ -67,10 +68,30 @@ func (o OpenLibertyDetector) DoPortsDetection(component *model.Component, ctx *c if err != nil { continue } - ports := utils.GetValidPorts([]string{data.HttpEndpoint.HttpPort, data.HttpEndpoint.HttpsPort}) + + variables := make(map[string]string) + for _, v := range data.Variables { + variables[v.Name] = v.DefaultValue + } + + httpPort := resolvePort(data.HttpEndpoint.HttpPort, variables) + httpsPort := resolvePort(data.HttpEndpoint.HttpsPort, variables) + + ports := utils.GetValidPorts([]string{httpPort, httpsPort}) if len(ports) > 0 { component.Ports = ports return } } } + +// resolvePort resolves the port value by checking if it is a variable and if it is, it returns the value of the variable +func resolvePort(portValue string, variables map[string]string) string { + if strings.HasPrefix(portValue, "${") && strings.HasSuffix(portValue, "}") { + varName := strings.Trim(portValue, "${}") + if value, exists := variables[varName]; exists { + return value + } + } + return portValue +} diff --git a/pkg/apis/model/model.go b/pkg/apis/model/model.go index 12594947..6bde6ca6 100644 --- a/pkg/apis/model/model.go +++ b/pkg/apis/model/model.go @@ -180,6 +180,10 @@ type OpenLibertyServerXml struct { HttpPort string `xml:"httpPort,attr"` HttpsPort string `xml:"httpsPort,attr"` } `xml:"httpEndpoint"` + Variables []struct { + Name string `xml:"name,attr"` + DefaultValue string `xml:"defaultValue,attr"` + } `xml:"variable"` } // PortDetectionAlgorithm represents one of port detection algorithm values diff --git a/pkg/utils/detector.go b/pkg/utils/detector.go index d1441141..99a7e814 100644 --- a/pkg/utils/detector.go +++ b/pkg/utils/detector.go @@ -21,12 +21,12 @@ import ( "fmt" "io" "io/fs" + "net/http" "os" "path/filepath" "regexp" "strconv" "strings" - "net/http" "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/schema" @@ -139,7 +139,7 @@ func GetPomFileContent(pomFilePath string) (schema.Pom, error) { if err != nil { return schema.Pom{}, err } - + var pom schema.Pom err = xml.Unmarshal(byteValue, &pom) if err != nil { @@ -568,9 +568,9 @@ func GetAnyApplicationFilePathExactMatch(root string, propsFiles []model.Applica func GenerateApplicationFileFromFilters(files []string, path string, suffix string, ctx *context.Context) []model.ApplicationFileInfo { applicationFileInfos := []model.ApplicationFileInfo{} for _, file := range files { - if strings.HasSuffix(file, suffix) && !strings.HasSuffix(file, "_test.go"){ + if strings.HasSuffix(file, suffix) && !strings.HasSuffix(file, "_test.go") { applicationFileInfos = append(applicationFileInfos, createAppFileInfo(file, path, ctx)) - } + } } return applicationFileInfos } @@ -751,13 +751,13 @@ func NormalizeSplit(file string) (string, string) { return dir, fileName } -func CloseHttpResponseBody(resp *http.Response){ +func CloseHttpResponseBody(resp *http.Response) { if err := resp.Body.Close(); err != nil { fmt.Printf("error closing file: %s", err) } } -func CloseFile(file *os.File){ +func CloseFile(file *os.File) { if err := file.Close(); err != nil { fmt.Printf("error closing file: %s", err) } diff --git a/test/apis/component_recognizer_test.go b/test/apis/component_recognizer_test.go index c803a4b7..f3d23ec0 100644 --- a/test/apis/component_recognizer_test.go +++ b/test/apis/component_recognizer_test.go @@ -158,6 +158,7 @@ func TestPortDetectionJavaMicronautFromDockerfileWithSSLEnabled(t *testing.T) { func TestPortDetectionOnOpenLiberty(t *testing.T) { testPortDetectionInProject(t, "open-liberty", []int{9080, 9443}) + testOpenLibertyDetector_DoPortsDetection(t, "open-liberty", []int{9080, 9443}) } func TestPortDetectionJavaQuarkus(t *testing.T) { diff --git a/test/apis/utils.go b/test/apis/utils.go index 6e47f3c4..927633ce 100644 --- a/test/apis/utils.go +++ b/test/apis/utils.go @@ -10,8 +10,10 @@ import ( "strings" "testing" + framework "github.com/devfile/alizer/pkg/apis/enricher/framework/java" "github.com/devfile/alizer/pkg/apis/model" "github.com/devfile/alizer/pkg/apis/recognizer" + "github.com/stretchr/testify/assert" ) func updateContent(filePath string, data []byte) error { @@ -19,7 +21,7 @@ func updateContent(filePath string, data []byte) error { if err != nil { return err } - defer func(){ + defer func() { if err := f.Close(); err != nil { fmt.Printf("error closing file: %s", err) } @@ -103,3 +105,87 @@ func getTestProjectPath(folder string) string { basepath := filepath.Dir(b) return filepath.Join(basepath, "..", "..", "resources/projects", folder) } + +func testOpenLibertyDetector_DoPortsDetection(t *testing.T, projectType string, expectedPorts []int) { + tempDir, err := os.MkdirTemp("", projectType+"-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + hardcodedXML := ` + + + + ` + writeTestFile(t, tempDir, "hardcoded_server.xml", hardcodedXML) + + variableXML := ` + + + + + + ` + writeTestFile(t, tempDir, "variable_server.xml", variableXML) + + mixedXML := ` + + + + + ` + writeTestFile(t, tempDir, "mixed_server.xml", mixedXML) + + emptyVarXML := ` + + + + + + ` + writeTestFile(t, tempDir, "empty_var_server.xml", emptyVarXML) + + detector := framework.OpenLibertyDetector{} + ctx := context.TODO() + + t.Run("Hardcoded Ports", func(t *testing.T) { + component := &model.Component{ + Path: filepath.Join(tempDir, "hardcoded_server.xml"), + } + detector.DoPortsDetection(component, &ctx) + assert.Equal(t, []int{1234, 1235}, component.Ports) + }) + + t.Run("Variable-based Ports", func(t *testing.T) { + component := &model.Component{ + Path: filepath.Join(tempDir, "variable_server.xml"), + } + detector.DoPortsDetection(component, &ctx) + assert.Equal(t, expectedPorts, component.Ports) + }) + + t.Run("Mixed Hardcoded and Variable Ports", func(t *testing.T) { + component := &model.Component{ + Path: filepath.Join(tempDir, "mixed_server.xml"), + } + detector.DoPortsDetection(component, &ctx) + assert.Equal(t, []int{9080, 1235}, component.Ports) + }) + + t.Run("Empty Variable Port", func(t *testing.T) { + component := &model.Component{ + Path: filepath.Join(tempDir, "empty_var_server.xml"), + } + detector.DoPortsDetection(component, &ctx) + assert.Equal(t, []int{9443}, component.Ports) + }) +} + +func writeTestFile(t *testing.T, dir, filename, content string) { + path := filepath.Join(dir, filename) + err := os.WriteFile(path, []byte(content), 0644) + if err != nil { + t.Fatal(err) + } +}