test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java
branchJDK-8200758-branch
changeset 58416 f09bf58c1f17
parent 58301 e0efb29609bd
child 58417 67ffaf3a2b75
equal deleted inserted replaced
58415:73f8e557549a 58416:f09bf58c1f17
    20  * or visit www.oracle.com if you need additional information or have any
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 package jdk.jpackage.test;
    23 package jdk.jpackage.test;
    24 
    24 
       
    25 import java.io.BufferedReader;
       
    26 import java.io.ByteArrayOutputStream;
    25 import java.io.IOException;
    27 import java.io.IOException;
    26 import java.io.PrintWriter;
    28 import java.io.InputStreamReader;
    27 import java.io.StringWriter;
    29 import java.io.OutputStream;
    28 import java.nio.file.Files;
    30 import java.io.PrintStream;
       
    31 import java.io.StringReader;
    29 import java.nio.file.Path;
    32 import java.nio.file.Path;
    30 import java.util.ArrayList;
    33 import java.util.ArrayList;
    31 import java.util.Arrays;
    34 import java.util.Arrays;
    32 import java.util.Collections;
    35 import java.util.Collections;
       
    36 import java.util.HashSet;
    33 import java.util.List;
    37 import java.util.List;
    34 import java.util.regex.Matcher;
    38 import java.util.Set;
    35 import java.util.regex.Pattern;
    39 import java.util.regex.Pattern;
    36 import java.util.spi.ToolProvider;
    40 import java.util.spi.ToolProvider;
    37 import java.util.stream.Collectors;
    41 import java.util.stream.Collectors;
    38 import java.util.stream.Stream;
    42 import java.util.stream.Stream;
       
    43 import jdk.jpackage.test.Functional.ThrowingSupplier;
    39 
    44 
    40 public final class Executor extends CommandArguments<Executor> {
    45 public final class Executor extends CommandArguments<Executor> {
    41 
    46 
    42     public Executor() {
    47     public Executor() {
    43         saveOutputType = SaveOutputType.NONE;
    48         saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE));
    44     }
    49     }
    45 
    50 
    46     public Executor setExecutable(String v) {
    51     public Executor setExecutable(String v) {
       
    52         return setExecutable(Path.of(v));
       
    53     }
       
    54 
       
    55     public Executor setExecutable(Path v) {
    47         executable = v;
    56         executable = v;
    48         if (executable != null) {
    57         if (executable != null) {
    49             toolProvider = null;
    58             toolProvider = null;
    50         }
    59         }
    51         return this;
    60         return this;
    52     }
    61     }
    53 
    62 
    54     public Executor setToolProvider(ToolProvider v) {
    63     public Executor setToolProvider(ToolProvider v) {
    55         toolProvider = v;
    64         toolProvider = v;
       
    65         filterOutJcovOutput = true;
    56         if (toolProvider != null) {
    66         if (toolProvider != null) {
    57             executable = null;
    67             executable = null;
    58         }
    68         }
    59         return this;
    69         return this;
    60     }
    70     }
    63         directory = v;
    73         directory = v;
    64         return this;
    74         return this;
    65     }
    75     }
    66 
    76 
    67     public Executor setExecutable(JavaTool v) {
    77     public Executor setExecutable(JavaTool v) {
    68         return setExecutable(v.getPath().getAbsolutePath());
    78         filterOutJcovOutput = true;
    69     }
    79         return setExecutable(v.getPath());
    70 
    80     }
       
    81 
       
    82     /**
       
    83      * Configures this instance to save full output that command will produce.
       
    84      * This function is mutual exclusive with
       
    85      * saveFirstLineOfOutput() function.
       
    86      *
       
    87      * @return this
       
    88      */
    71     public Executor saveOutput() {
    89     public Executor saveOutput() {
    72         saveOutputType = SaveOutputType.FULL;
    90         saveOutputType.remove(SaveOutputType.FIRST_LINE);
    73         return this;
    91         saveOutputType.add(SaveOutputType.FULL);
    74     }
    92         return this;
    75 
    93     }
       
    94 
       
    95     /**
       
    96      * Configures how to save output that command will produce. If
       
    97      * <code>v</code> is <code>true</code>, the function call is equivalent to
       
    98      * <code>saveOutput()</code> call. If <code>v</code> is <code>false</code>,
       
    99      * the function will result in not preserving command output.
       
   100      *
       
   101      * @return this
       
   102      */
       
   103     public Executor saveOutput(boolean v) {
       
   104         if (v) {
       
   105             saveOutput();
       
   106         } else {
       
   107             saveOutputType.remove(SaveOutputType.FIRST_LINE);
       
   108             saveOutputType.remove(SaveOutputType.FULL);
       
   109         }
       
   110         return this;
       
   111     }
       
   112 
       
   113     /**
       
   114      * Configures this instance to save only the first line out output that
       
   115      * command will produce. This function is mutual exclusive with
       
   116      * saveOutput() function.
       
   117      *
       
   118      * @return this
       
   119      */
    76     public Executor saveFirstLineOfOutput() {
   120     public Executor saveFirstLineOfOutput() {
    77         saveOutputType = SaveOutputType.FIRST_LINE;
   121         saveOutputType.add(SaveOutputType.FIRST_LINE);
    78         return this;
   122         saveOutputType.remove(SaveOutputType.FULL);
    79     }
   123         return this;
    80 
   124     }
    81     public Executor dumpOtput() {
   125 
    82         saveOutputType = SaveOutputType.DUMP;
   126     /**
       
   127      * Configures this instance to dump all output that command will produce to
       
   128      * System.out and System.err. Can be used together with saveOutput() and
       
   129      * saveFirstLineOfOutput() to save command output and also copy it in the
       
   130      * default output streams.
       
   131      *
       
   132      * @return this
       
   133      */
       
   134     public Executor dumpOutput() {
       
   135         return dumpOutput(true);
       
   136     }
       
   137 
       
   138     public Executor dumpOutput(boolean v) {
       
   139         if (v) {
       
   140             saveOutputType.add(SaveOutputType.DUMP);
       
   141         } else {
       
   142             saveOutputType.remove(SaveOutputType.DUMP);
       
   143         }
    83         return this;
   144         return this;
    84     }
   145     }
    85 
   146 
    86     public class Result {
   147     public class Result {
    87 
   148 
   100         public String getPrintableCommandLine() {
   161         public String getPrintableCommandLine() {
   101             return Executor.this.getPrintableCommandLine();
   162             return Executor.this.getPrintableCommandLine();
   102         }
   163         }
   103 
   164 
   104         public Result assertExitCodeIs(int expectedExitCode) {
   165         public Result assertExitCodeIs(int expectedExitCode) {
   105             Test.assertEquals(expectedExitCode, exitCode, String.format(
   166             TKit.assertEquals(expectedExitCode, exitCode, String.format(
   106                     "Check command %s exited with %d code",
   167                     "Check command %s exited with %d code",
   107                     getPrintableCommandLine(), expectedExitCode));
   168                     getPrintableCommandLine(), expectedExitCode));
   108             return this;
   169             return this;
   109         }
   170         }
   110 
   171 
   115         final int exitCode;
   176         final int exitCode;
   116         private List<String> output;
   177         private List<String> output;
   117     }
   178     }
   118 
   179 
   119     public Result execute() {
   180     public Result execute() {
   120         if (toolProvider != null) {
   181         return ThrowingSupplier.toSupplier(() -> {
   121             return runToolProvider();
   182             if (toolProvider != null) {
   122         }
   183                 return runToolProvider();
   123 
   184             }
   124         try {
   185 
   125             if (executable != null) {
   186             if (executable != null) {
   126                 return runExecutable();
   187                 return runExecutable();
   127             }
   188             }
   128         } catch (RuntimeException e) {
   189 
   129             throw e;
   190             throw new IllegalStateException("No command to execute");
   130         } catch (IOException | InterruptedException e) {
   191         }).get();
   131             throw new RuntimeException(e);
       
   132         }
       
   133 
       
   134         throw new IllegalStateException("No command to execute");
       
   135     }
   192     }
   136 
   193 
   137     public String executeAndGetFirstLineOfOutput() {
   194     public String executeAndGetFirstLineOfOutput() {
   138         return saveFirstLineOfOutput().execute().assertExitCodeIsZero().getFirstLineOfOutput();
   195         return saveFirstLineOfOutput().execute().assertExitCodeIsZero().getFirstLineOfOutput();
   139     }
   196     }
   140 
   197 
   141     public List<String> executeAndGetOutput() {
   198     public List<String> executeAndGetOutput() {
   142         return saveOutput().execute().assertExitCodeIsZero().getOutput();
   199         return saveOutput().execute().assertExitCodeIsZero().getOutput();
   143     }
   200     }
   144 
   201 
       
   202     private boolean withSavedOutput() {
       
   203         return saveOutputType.contains(SaveOutputType.FULL) || saveOutputType.contains(
       
   204                 SaveOutputType.FIRST_LINE);
       
   205     }
       
   206 
   145     private Result runExecutable() throws IOException, InterruptedException {
   207     private Result runExecutable() throws IOException, InterruptedException {
   146         List<String> command = new ArrayList<>();
   208         List<String> command = new ArrayList<>();
   147         command.add(executable);
   209         command.add(executable.toString());
   148         command.addAll(args);
   210         command.addAll(args);
   149         Path outputFile = null;
       
   150         ProcessBuilder builder = new ProcessBuilder(command);
   211         ProcessBuilder builder = new ProcessBuilder(command);
   151         StringBuilder sb = new StringBuilder(getPrintableCommandLine());
   212         StringBuilder sb = new StringBuilder(getPrintableCommandLine());
   152         if (saveOutputType != SaveOutputType.NONE) {
   213         if (withSavedOutput()) {
   153             builder.redirectErrorStream(true);
   214             builder.redirectErrorStream(true);
   154 
   215             sb.append("; save output");
   155             if (saveOutputType == SaveOutputType.DUMP) {
   216         } else if (saveOutputType.contains(SaveOutputType.DUMP)) {
   156                 builder.inheritIO();
   217             builder.inheritIO();
   157                 sb.append("; redirect output to stdout");
   218             sb.append("; inherit I/O");
   158             } else {
       
   159                 outputFile = Test.createTempFile(".out");
       
   160                 builder.redirectOutput(outputFile.toFile());
       
   161                 sb.append(String.format("; redirect output to [%s]", outputFile));
       
   162             }
       
   163         }
   219         }
   164         if (directory != null) {
   220         if (directory != null) {
   165             builder.directory(directory.toFile());
   221             builder.directory(directory.toFile());
   166             sb.append(String.format("; in directory [%s]", directory));
   222             sb.append(String.format("; in directory [%s]", directory));
   167         }
   223         }
   168 
   224 
   169         try {
   225         TKit.trace("Execute " + sb.toString() + "...");
   170             Test.trace("Execute " + sb.toString() + "...");
   226         Process process = builder.start();
   171             Process process = builder.start();
   227 
   172             Result reply = new Result(process.waitFor());
   228         List<String> outputLines = null;
   173             Test.trace("Done. Exit code: " + reply.exitCode);
   229         if (withSavedOutput()) {
   174             if (saveOutputType == SaveOutputType.FIRST_LINE) {
   230             try (BufferedReader outReader = new BufferedReader(
   175                 // If the command produced no ouput, save null in 'result.output' list.
   231                     new InputStreamReader(process.getInputStream()))) {
   176                 reply.output = Arrays.asList(
   232                 if (saveOutputType.contains(SaveOutputType.DUMP) || saveOutputType.contains(
   177                         Files.readAllLines(outputFile).stream().findFirst().orElse(
   233                         SaveOutputType.FULL)) {
   178                                 null));
   234                     outputLines = outReader.lines().collect(Collectors.toList());
   179             } else if (saveOutputType == SaveOutputType.FULL) {
   235                 } else {
   180                 reply.output = Collections.unmodifiableList(Files.readAllLines(
   236                     outputLines = Arrays.asList(
   181                         outputFile));
   237                             outReader.lines().findFirst().orElse(null));
       
   238                 }
       
   239             } finally {
       
   240                 if (saveOutputType.contains(SaveOutputType.DUMP) && outputLines != null) {
       
   241                     outputLines.stream().forEach(System.out::println);
       
   242                     if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) {
       
   243                         // Pick the first line of saved output if there is one
       
   244                         for (String line: outputLines) {
       
   245                             outputLines = List.of(line);
       
   246                             break;
       
   247                         }
       
   248                     }
       
   249                 }
       
   250             }
       
   251         }
       
   252 
       
   253         Result reply = new Result(process.waitFor());
       
   254         TKit.trace("Done. Exit code: " + reply.exitCode);
       
   255 
       
   256         if (outputLines != null) {
       
   257             reply.output = Collections.unmodifiableList(outputLines);
       
   258         }
       
   259         return reply;
       
   260     }
       
   261 
       
   262     private Result runToolProvider(PrintStream out, PrintStream err) {
       
   263         TKit.trace("Execute " + getPrintableCommandLine() + "...");
       
   264         Result reply = new Result(toolProvider.run(out, err, args.toArray(
       
   265                 String[]::new)));
       
   266         TKit.trace("Done. Exit code: " + reply.exitCode);
       
   267         return reply;
       
   268     }
       
   269 
       
   270 
       
   271     private Result runToolProvider() throws IOException {
       
   272         if (!withSavedOutput()) {
       
   273             if (saveOutputType.contains(SaveOutputType.DUMP)) {
       
   274                 return runToolProvider(System.out, System.err);
       
   275             }
       
   276 
       
   277             PrintStream nullPrintStream = new PrintStream(new OutputStream() {
       
   278                 @Override
       
   279                 public void write(int b) {
       
   280                     // Nop
       
   281                 }
       
   282             });
       
   283             return runToolProvider(nullPrintStream, nullPrintStream);
       
   284         }
       
   285 
       
   286         try (ByteArrayOutputStream buf = new ByteArrayOutputStream();
       
   287                 PrintStream ps = new PrintStream(buf)) {
       
   288             Result reply = runToolProvider(ps, ps);
       
   289             ps.flush();
       
   290             try (BufferedReader bufReader = new BufferedReader(new StringReader(
       
   291                     buf.toString()))) {
       
   292                 if (saveOutputType.contains(SaveOutputType.FIRST_LINE)) {
       
   293                     String firstLine = filterJcovOutput(bufReader.lines()).findFirst().orElse(
       
   294                             null);
       
   295                     if (firstLine != null) {
       
   296                         reply.output = List.of(firstLine);
       
   297                     }
       
   298                 } else if (saveOutputType.contains(SaveOutputType.FULL)) {
       
   299                     reply.output = filterJcovOutput(bufReader.lines()).collect(
       
   300                             Collectors.toUnmodifiableList());
       
   301                 }
       
   302 
       
   303                 if (saveOutputType.contains(SaveOutputType.DUMP)) {
       
   304                     Stream<String> lines;
       
   305                     if (saveOutputType.contains(SaveOutputType.FULL)) {
       
   306                         lines = reply.output.stream();
       
   307                     } else {
       
   308                         lines = bufReader.lines();
       
   309                     }
       
   310                     lines.forEach(System.out::println);
       
   311                 }
   182             }
   312             }
   183             return reply;
   313             return reply;
   184         } finally {
   314         }
   185             if (outputFile != null) {
       
   186                 Files.deleteIfExists(outputFile);
       
   187             }
       
   188         }
       
   189     }
       
   190 
       
   191     private Result runToolProvider() {
       
   192         StringWriter writer = new StringWriter();
       
   193         PrintWriter pw = new PrintWriter(writer);
       
   194 
       
   195         Test.trace("Execute " + getPrintableCommandLine() + "...");
       
   196         Result reply = new Result(toolProvider.run(pw, pw, args.toArray(
       
   197                 String[]::new)));
       
   198         Test.trace("Done. Exit code: " + reply.exitCode);
       
   199 
       
   200         List lines = List.of(writer.toString().split("\\R", -1));
       
   201 
       
   202         if (saveOutputType == SaveOutputType.FIRST_LINE) {
       
   203             reply.output = Stream.of(lines).findFirst().get();
       
   204         } else if (saveOutputType == SaveOutputType.FULL) {
       
   205             reply.output = Collections.unmodifiableList(lines);
       
   206         }
       
   207         return reply;
       
   208     }
   315     }
   209 
   316 
   210     public String getPrintableCommandLine() {
   317     public String getPrintableCommandLine() {
   211         final String exec;
   318         final String exec;
   212         String format = "[%s](%d)";
   319         String format = "[%s](%d)";
   214             exec = "<null>";
   321             exec = "<null>";
   215         } else if (toolProvider != null) {
   322         } else if (toolProvider != null) {
   216             format = "tool provider " + format;
   323             format = "tool provider " + format;
   217             exec = toolProvider.name();
   324             exec = toolProvider.name();
   218         } else {
   325         } else {
   219             exec = executable;
   326             exec = executable.toString();
   220         }
   327         }
   221 
   328 
   222         return String.format(format, printCommandLine(exec, args),
   329         return String.format(format, printCommandLine(exec, args),
   223                 args.size() + 1);
   330                 args.size() + 1);
   224     }
   331     }
   230         return Stream.concat(Stream.of(executable), args.stream()).map(
   337         return Stream.concat(Stream.of(executable), args.stream()).map(
   231                 v -> (v.isEmpty() || regex.matcher(v).find()) ? "\"" + v + "\"" : v).collect(
   338                 v -> (v.isEmpty() || regex.matcher(v).find()) ? "\"" + v + "\"" : v).collect(
   232                         Collectors.joining(" "));
   339                         Collectors.joining(" "));
   233     }
   340     }
   234 
   341 
       
   342     private Stream<String> filterJcovOutput(Stream<String> lines) {
       
   343         if (filterOutJcovOutput) {
       
   344             return lines.filter(line -> !line.startsWith("Picked up"));
       
   345         }
       
   346         return lines;
       
   347     }
       
   348 
   235     private ToolProvider toolProvider;
   349     private ToolProvider toolProvider;
   236     private String executable;
   350     private Path executable;
   237     private SaveOutputType saveOutputType;
   351     private Set<SaveOutputType> saveOutputType;
   238     private Path directory;
   352     private Path directory;
       
   353     private boolean filterOutJcovOutput;
   239 
   354 
   240     private static enum SaveOutputType {
   355     private static enum SaveOutputType {
   241         NONE, FULL, FIRST_LINE, DUMP
   356         NONE, FULL, FIRST_LINE, DUMP
   242     };
   357     };
   243 }
   358 }