Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/integration/tomcat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,41 @@ func testTomcat(platform switchblade.Platform, fixtures string) func(*testing.T,
})

context("with a simple servlet app", func() {
it("successfully deploys and runs with Java 11 (Javax)", func() {
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"BP_JAVA_VERSION": "11",
"JBP_CONFIG_TOMCAT": "{tomcat: { version: \"9.+\" }, access_logging_support: {access_logging: enabled}}",
}).
Execute(name, filepath.Join(fixtures, "containers", "tomcat_javax"))

Expect(err).NotTo(HaveOccurred(), logs.String)

// Verify embedded Cloud Foundry-optimized Tomcat configuration was installed
Expect(logs.String()).To(ContainSubstring("Installing Cloud Foundry-optimized Tomcat configuration defaults"))
Expect(logs.String()).To(ContainSubstring("Dynamic port binding (${http.port} from $PORT)"))
Expect(logs.String()).To(ContainSubstring("HTTP/2 support enabled"))
Expect(logs.String()).To(ContainSubstring("RemoteIpValve for X-Forwarded-* headers"))
Expect(logs.String()).To(ContainSubstring("CloudFoundryAccessLoggingValve with vcap_request_id"))
Expect(logs.String()).To(ContainSubstring("Stdout logging via CloudFoundryConsoleHandler"))

Eventually(deployment).Should(matchers.Serve(ContainSubstring("OK")))

// Verify runtime logs contain CloudFoundry-specific Tomcat features
// Use Eventually to wait for logs to be flushed, as they may not appear immediately

// Check for HTTP/2 support in runtime logs (Tomcat startup messages)
// These should appear quickly during Tomcat startup
Eventually(func() string {
logs, _ := deployment.RuntimeLogs()
return logs
}, "10s", "1s").Should(Or(
ContainSubstring("Http11NioProtocol"),
ContainSubstring("Starting ProtocolHandler"),
ContainSubstring("HTTP/1.1"),
))
})

it("successfully deploys and runs with Java 11 (Jakarta EE)", func() {
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
Expand Down Expand Up @@ -140,6 +175,33 @@ func testTomcat(platform switchblade.Platform, fixtures string) func(*testing.T,
Eventually(deployment).Should(matchers.Serve(ContainSubstring("OK")))
})

it("deploys with Java 11 (Tomcat 9 + javax.servlet)", func() {
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"BP_JAVA_VERSION": "11",
"JBP_CONFIG_TOMCAT": "{tomcat: { version: \"9.+\" }",
}).
Execute(name, filepath.Join(fixtures, "containers", "tomcat_javax"))
Expect(err).NotTo(HaveOccurred(), logs.String)

Expect(logs.String()).To(ContainSubstring("Installing OpenJDK 11."))
Expect(logs.String()).To(ContainSubstring("Tomcat 9"))
Eventually(deployment).Should(matchers.Serve(ContainSubstring("OK")))
})

it("deploys with default Java (Tomcat 9 + javax.servlet)", func() {
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"JBP_CONFIG_TOMCAT": "{ tomcat: { version: 9.+ } }",
}).
Execute(name, filepath.Join(fixtures, "containers", "tomcat_javax"))
Expect(err).NotTo(HaveOccurred(), logs.String)

Expect(logs.String()).To(ContainSubstring("Installing OpenJDK 17."))
Expect(logs.String()).To(ContainSubstring("Tomcat 9"))
Eventually(deployment).Should(matchers.Serve(ContainSubstring("OK")))
})

it("deploys with Java 11 (Tomcat 10 + jakarta.servlet)", func() {
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
Expand Down
12 changes: 12 additions & 0 deletions src/java/common/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
)
Expand Down Expand Up @@ -50,6 +51,17 @@ type Context struct {
Command Command
}

// DetermineTomcatVersion determines the version of the tomcat
// based on the JBP_CONFIG_TOMCAT field from manifest
func DetermineTomcatVersion(raw string) (string, error) {
re := regexp.MustCompile(`(\d+)`)
match := re.FindStringSubmatch(raw)
if len(match) < 2 {
return "", fmt.Errorf("unable to extract Tomcat version from %q", raw)
}
return match[1] + ".x", nil
}

// DetermineJavaVersion determines the major Java version from a Java installation
// by reading the JAVA_VERSION field from the release file.
//
Expand Down
20 changes: 13 additions & 7 deletions src/java/containers/tomcat.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,24 @@ func (t *TomcatContainer) Supply() error {
if javaHome != "" {
javaMajorVersion, versionErr := common.DetermineJavaVersion(javaHome)
if versionErr == nil {
tomcatVersion, err := common.DetermineTomcatVersion(os.Getenv("JBP_CONFIG_TOMCAT"))
t.context.Log.Debug("Detected Java major version: %d", javaMajorVersion)

// Select Tomcat version pattern based on Java version
var versionPattern string
if javaMajorVersion >= 11 {
// Java 11+: Use Tomcat 10.x (Jakarta EE 9+)
versionPattern = "10.x"
t.context.Log.Info("Using Tomcat 10.x for Java %d", javaMajorVersion)
if tomcatVersion == "" {
if javaMajorVersion >= 11 {
// Java 11+: Use Tomcat 10.x (Jakarta EE 9+)
versionPattern = "10.x"
t.context.Log.Info("Using Tomcat 10.x for Java %d", javaMajorVersion)
} else {
// Java 8-10: Use Tomcat 9.x (Java EE 8)
versionPattern = "9.x"
t.context.Log.Info("Using Tomcat 9.x for Java %d", javaMajorVersion)
}
} else {
// Java 8-10: Use Tomcat 9.x (Java EE 8)
versionPattern = "9.x"
t.context.Log.Info("Using Tomcat 9.x for Java %d", javaMajorVersion)
versionPattern = tomcatVersion
t.context.Log.Info("Using Tomcat %s for Java %d", versionPattern, javaMajorVersion)
}

// Resolve the version pattern to actual version using libbuildpack
Expand Down