Переглянути джерело

Adjust terminal tests to new behavior in JDK 22. (#103614)

JDK 22 may return a console even if the terminal is redirected. These cases are detected using the new Console#isTerminal() to maintain the current behavior (closes #98033).
Moritz Mack 1 рік тому
батько
коміт
9f8088daec

+ 4 - 1
libs/cli/build.gradle

@@ -11,9 +11,12 @@ apply plugin: 'elasticsearch.publish'
 dependencies {
   api 'net.sf.jopt-simple:jopt-simple:5.0.2'
   api project(':libs:elasticsearch-core')
+
+  testImplementation(project(":test:framework")) {
+    exclude group: 'org.elasticsearch', module: 'elasticsearch-cli'
+  }
 }
 
-tasks.named("test").configure { enabled = false }
 // Since CLI does not depend on :server, it cannot run the jarHell task
 tasks.named("jarHell").configure { enabled = false }
 

+ 21 - 2
libs/cli/src/main/java/org/elasticsearch/cli/Terminal.java

@@ -18,6 +18,8 @@ import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Locale;
@@ -274,8 +276,8 @@ public abstract class Terminal {
     }
 
     private static class ConsoleTerminal extends Terminal {
-
-        private static final Console CONSOLE = System.console();
+        private static final int JDK_VERSION_WITH_IS_TERMINAL = 22;
+        private static final Console CONSOLE = detectTerminal();
 
         ConsoleTerminal() {
             super(CONSOLE.reader(), CONSOLE.writer(), ERROR_WRITER);
@@ -285,6 +287,23 @@ public abstract class Terminal {
             return CONSOLE != null;
         }
 
+        static Console detectTerminal() {
+            // JDK >= 22 returns a console even if the terminal is redirected unless using -Djdk.console=java.base
+            // https://bugs.openjdk.org/browse/JDK-8308591
+            Console console = System.console();
+            if (console != null && Runtime.version().feature() >= JDK_VERSION_WITH_IS_TERMINAL) {
+                try {
+                    // verify the console is a terminal using isTerminal() on JDK >= 22
+                    // TODO: Remove reflection once Java 22 sources are supported, e.g. using a MRJAR
+                    Method isTerminal = Console.class.getMethod("isTerminal");
+                    return Boolean.TRUE.equals(isTerminal.invoke(console)) ? console : null;
+                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+                    throw new AssertionError(e);
+                }
+            }
+            return console;
+        }
+
         @Override
         public String readText(String prompt) {
             return CONSOLE.readLine("%s", prompt);

+ 23 - 0
libs/cli/src/test/java/org/elasticsearch/cli/TerminalTests.java

@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.cli;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.ESTestCase.WithoutSecurityManager;
+
+@WithoutSecurityManager
+public class TerminalTests extends ESTestCase {
+
+    public void testSystemTerminalIfRedirected() {
+        // Expect system terminal if redirected for tests.
+        // To force new behavior in JDK 22 this should run without security manager.
+        // Otherwise, JDK 22 doesn't provide a console if redirected.
+        assertEquals(Terminal.SystemTerminal.class, Terminal.DEFAULT.getClass());
+    }
+}