diff --git a/cli/cmd/server.go b/cli/cmd/server.go index d65a55f9..b060f04c 100644 --- a/cli/cmd/server.go +++ b/cli/cmd/server.go @@ -42,6 +42,7 @@ var ( serverFindLocalJAR = findLocalJAR serverCheckJava = checkJava serverCheckAIProviderKeys = checkAIProviderKeys + serverLaunch = launchServer ) var serverCmd = &cobra.Command{ @@ -101,6 +102,22 @@ func logFile() string { func runServerStart(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true + + // Validate JDK before doing anything + javaOk, javaVersion := serverCheckJava() + if !javaOk { + if javaVersion != "" { + return fmt.Errorf( + "Java %s detected but Java 21+ is required.\n"+ + " Install Java 21+: https://adoptium.net/\n"+ + " Run 'agentspan doctor' for full diagnostics.", javaVersion) + } + return fmt.Errorf( + "Java is not installed. The Agentspan server requires Java 21+.\n" + + " Install: https://adoptium.net/\n" + + " Run 'agentspan doctor' for full diagnostics.") + } + dir := serverDir() if err := os.MkdirAll(dir, 0o755); err != nil { return fmt.Errorf("create server dir: %w", err) @@ -160,21 +177,10 @@ func runServerStart(cmd *cobra.Command, args []string) error { serverCheckAIProviderKeys() - // Validate JDK before launching java - javaOk, javaVersion := serverCheckJava() - if !javaOk { - if javaVersion != "" { - return fmt.Errorf( - "Java %s detected but Java 21+ is required.\n"+ - " Install Java 21+: https://adoptium.net/\n"+ - " Run 'agentspan doctor' for full diagnostics.", javaVersion) - } - return fmt.Errorf( - "Java is not installed. The Agentspan server requires Java 21+.\n" + - " Install: https://adoptium.net/\n" + - " Run 'agentspan doctor' for full diagnostics.") - } + return serverLaunch(jarPath, dir) +} +func launchServer(jarPath, dir string) error { bold := color.New(color.Bold) bold.Printf("Starting agent runtime on port %s...\n", serverPort) diff --git a/cli/cmd/server_test.go b/cli/cmd/server_test.go index 27ee27e7..8f35ed05 100644 --- a/cli/cmd/server_test.go +++ b/cli/cmd/server_test.go @@ -111,6 +111,7 @@ func TestServerStartUsesRequestedVersion(t *testing.T) { prevCheckJava := serverCheckJava prevCheckAI := serverCheckAIProviderKeys prevProcessRunning := serverProcessRunning + prevLaunch := serverLaunch prevServerJar := serverJar prevServerLocal := serverLocal prevServerVersion := serverVersion @@ -123,6 +124,7 @@ func TestServerStartUsesRequestedVersion(t *testing.T) { serverCheckJava = prevCheckJava serverCheckAIProviderKeys = prevCheckAI serverProcessRunning = prevProcessRunning + serverLaunch = prevLaunch serverJar = prevServerJar serverLocal = prevServerLocal serverVersion = prevServerVersion @@ -154,14 +156,11 @@ func TestServerStartUsesRequestedVersion(t *testing.T) { return "", nil } serverCheckAIProviderKeys = func() {} - serverCheckJava = func() (bool, string) { return false, "" } + serverCheckJava = func() (bool, string) { return true, "21.0.1" } + serverLaunch = func(jarPath, dir string) error { return nil } - err := runServerStart(serverStartCmd, nil) - if err == nil { - t.Fatal("expected runServerStart to stop at Java validation in test") - } - if !strings.Contains(err.Error(), "Java is not installed") { - t.Fatalf("unexpected error: %v", err) + if err := runServerStart(serverStartCmd, nil); err != nil { + t.Fatalf("runServerStart returned error: %v", err) } if !versionedCalled { t.Fatal("expected versioned JAR downloader to be called") @@ -175,6 +174,50 @@ func TestServerStartUsesRequestedVersion(t *testing.T) { } } +func TestServerStartFailsWhenJavaMissing(t *testing.T) { + newTempHome(t) + + prevCheckJava := serverCheckJava + prevLaunch := serverLaunch + prevEnsureLatest := serverEnsureLatestJAR + prevEnsureVersioned := serverEnsureVersionedJAR + prevFindLocal := serverFindLocalJAR + t.Cleanup(func() { + serverCheckJava = prevCheckJava + serverLaunch = prevLaunch + serverEnsureLatestJAR = prevEnsureLatest + serverEnsureVersionedJAR = prevEnsureVersioned + serverFindLocalJAR = prevFindLocal + }) + + serverCheckJava = func() (bool, string) { return false, "" } + // Nothing below the Java check should be reached. + serverEnsureLatestJAR = func(string) error { + t.Fatal("ensureLatestJAR should not be called when Java is missing") + return nil + } + serverEnsureVersionedJAR = func(string, string) error { + t.Fatal("ensureVersionedJAR should not be called when Java is missing") + return nil + } + serverFindLocalJAR = func() (string, error) { + t.Fatal("findLocalJAR should not be called when Java is missing") + return "", nil + } + serverLaunch = func(jarPath, dir string) error { + t.Fatal("launchServer should not be called when Java is missing") + return nil + } + + err := runServerStart(serverStartCmd, nil) + if err == nil { + t.Fatal("expected an error when Java is missing") + } + if !strings.Contains(err.Error(), "Java is not installed") { + t.Fatalf("unexpected error: %v", err) + } +} + func freeTCPPort(t *testing.T) string { t.Helper() ln, err := net.Listen("tcp", "127.0.0.1:0")