diff --git a/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs b/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs index 5e73382..b37a13e 100644 --- a/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs +++ b/src/LiquidCode.Tester.Worker/Services/Isolate/IsolateService.cs @@ -163,12 +163,16 @@ public class IsolateService if (!string.IsNullOrEmpty(options.StdoutFile)) { - args.Add($"--stdout={MapSandboxPath(options.StdoutFile, options.BoxId)}"); + var mappedStdout = MapSandboxPath(options.StdoutFile, options.BoxId); + _logger.LogDebug("Stdout mapping: {Original} -> {Mapped}", options.StdoutFile, mappedStdout); + args.Add($"--stdout={mappedStdout}"); } if (!string.IsNullOrEmpty(options.StderrFile)) { - args.Add($"--stderr={MapSandboxPath(options.StderrFile, options.BoxId)}"); + var mappedStderr = MapSandboxPath(options.StderrFile, options.BoxId); + _logger.LogDebug("Stderr mapping: {Original} -> {Mapped}", options.StderrFile, mappedStderr); + args.Add($"--stderr={mappedStderr}"); } // Working directory diff --git a/src/LiquidCode.Tester.Worker/Services/JavaCompilationServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/JavaCompilationServiceIsolate.cs index 394d2ba..aa086fe 100644 --- a/src/LiquidCode.Tester.Worker/Services/JavaCompilationServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/JavaCompilationServiceIsolate.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; using LiquidCode.Tester.Worker.Services.Isolate; using LiquidCode.Tester.Worker.Models; @@ -30,16 +32,18 @@ public class JavaCompilationServiceIsolate : ICompilationService public async Task CompileAsync(string sourceCode, string workingDirectory, string? version = null) { - var sourceFilePath = Path.Combine(workingDirectory, "Solution.java"); - var classFilePath = Path.Combine(workingDirectory, "Solution.class"); + // Extract class name from source code + var className = ExtractPublicClassName(sourceCode) ?? "Solution"; + var sourceFilePath = Path.Combine(workingDirectory, $"{className}.java"); + var classFilePath = Path.Combine(workingDirectory, $"{className}.class"); - _logger.LogInformation("Compiling Java code with Isolate in {WorkingDirectory} with version {Version}", - workingDirectory, version ?? "latest"); + _logger.LogInformation("Compiling Java code with Isolate in {WorkingDirectory} with version {Version}, class: {ClassName}", + workingDirectory, version ?? "latest", className); try { await File.WriteAllTextAsync(sourceFilePath, sourceCode); - return await CompileFileInIsolateAsync(sourceFilePath, classFilePath, workingDirectory, version); + return await CompileFileInIsolateAsync(sourceFilePath, classFilePath, workingDirectory, version, className); } catch (Exception ex) { @@ -52,11 +56,22 @@ public class JavaCompilationServiceIsolate : ICompilationService } } + /// + /// Extract public class name from Java source code + /// + private static string? ExtractPublicClassName(string sourceCode) + { + // Match "public class ClassName" (with optional generics, extends, implements) + var match = Regex.Match(sourceCode, @"public\s+class\s+(\w+)"); + return match.Success ? match.Groups[1].Value : null; + } + private async Task CompileFileInIsolateAsync( string sourceFilePath, string classFilePath, string workingDirectory, - string? version = null) + string? version = null, + string className = "Solution") { int boxId = -1; @@ -87,6 +102,13 @@ public class JavaCompilationServiceIsolate : ICompilationService var stderrFilePath = Path.Combine(boxDir, "compile_stderr.txt"); var stdoutFilePath = Path.Combine(boxDir, "compile_stdout.txt"); + // Create empty files for stdout/stderr (isolate might require them to exist) + await File.WriteAllTextAsync(stdoutFilePath, string.Empty); + await File.WriteAllTextAsync(stderrFilePath, string.Empty); + + _logger.LogDebug("Stdout will be written to: {StdoutPath}", stdoutFilePath); + _logger.LogDebug("Stderr will be written to: {StderrPath}", stderrFilePath); + var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions { BoxId = boxId, @@ -103,11 +125,16 @@ public class JavaCompilationServiceIsolate : ICompilationService WorkingDirectory = "/box", DirectoryBindings = new List { - new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true }, new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true }, new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true }, new DirectoryBinding { HostPath = "/lib64", SandboxPath = "/lib64", ReadOnly = true }, + new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true }, + new DirectoryBinding { HostPath = "/bin", SandboxPath = "/bin", ReadOnly = true }, new DirectoryBinding { HostPath = "/etc", SandboxPath = "/etc", ReadOnly = true } + }, + EnvironmentVariables = new Dictionary + { + ["PATH"] = "/usr/local/bin:/usr/bin:/bin" } }); @@ -122,6 +149,14 @@ public class JavaCompilationServiceIsolate : ICompilationService compilerOutput = stdoutContent; _logger.LogDebug("Read stdout file: {Length} bytes", stdoutContent.Length); } + else + { + _logger.LogDebug("Stdout file exists but is empty"); + } + } + else + { + _logger.LogWarning("Stdout file does not exist at {Path}", stdoutFilePath); } // Read stderr @@ -135,6 +170,14 @@ public class JavaCompilationServiceIsolate : ICompilationService : $"{compilerOutput}\n{stderrContent}"; _logger.LogDebug("Read stderr file: {Length} bytes", stderrContent.Length); } + else + { + _logger.LogDebug("Stderr file exists but is empty"); + } + } + else + { + _logger.LogWarning("Stderr file does not exist at {Path}", stderrFilePath); } if (!string.IsNullOrEmpty(isolateResult.ErrorOutput)) @@ -169,7 +212,7 @@ public class JavaCompilationServiceIsolate : ICompilationService } // Copy .class file back - var boxClassPath = Path.Combine(boxDir, "Solution.class"); + var boxClassPath = Path.Combine(boxDir, $"{className}.class"); if (isolateResult.ExitCode == 0 && File.Exists(boxClassPath)) { Directory.CreateDirectory(Path.GetDirectoryName(classFilePath)!); @@ -184,8 +227,8 @@ public class JavaCompilationServiceIsolate : ICompilationService }; } - _logger.LogWarning("Java compilation failed with exit code {ExitCode} in box {BoxId}", - isolateResult.ExitCode, boxId); + _logger.LogWarning("Java compilation failed with exit code {ExitCode} in box {BoxId}. Compiler output: {Output}", + isolateResult.ExitCode, boxId, compilerOutput); return new CompilationResult { Success = false, diff --git a/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs b/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs index 528b254..d2a82f4 100644 --- a/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs +++ b/src/LiquidCode.Tester.Worker/Services/JavaExecutionServiceIsolate.cs @@ -73,11 +73,14 @@ public class JavaExecutionServiceIsolate : IExecutionService var jvmHeapMb = memoryLimitMb; var jvmTotalMemoryMb = memoryLimitMb + 64; // Add 64MB for JVM overhead (metaspace, code cache, etc.) + // Extract class name from .class file path + var className = Path.GetFileNameWithoutExtension(executablePath); + var arguments = new List { $"-Xmx{jvmHeapMb}m", // Max heap size = requested memory limit $"-Xms{Math.Min(jvmHeapMb, 32)}m", // Initial heap size (min 32MB or requested) - "-cp", "/box", "Solution" + "-cp", "/box", className }; var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions