1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary.tasks; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * The supertype for tasks. 34 * Complex operations are modeled by building and running a "Task" object. 35 * Tasks are typically configured in a fluent series of calls. 36 */ 37 public interface Task { 38 39 /** 40 * {@code ALL-UNNAMED} 41 */ 42 static final String ALL_UNNAMED = "ALL-UNNAMED"; 43 44 /** The platform line separator. */ 45 static final String lineSeparator = System.getProperty("line.separator"); 46 /** 47 * Returns the name of the task. 48 * @return the name of the task 49 */ 50 String name(); 51 52 /** 53 * Executes the task as currently configured. 54 * @return a Result object containing the results of running the task 55 * @throws TaskError if the outcome of the task was not as expected 56 */ 57 Result run() throws TaskError; 58 59 /** 60 * Exception thrown by {@code Task.run} when the outcome is not as 61 * expected. 62 */ 63 public static class TaskError extends Error { 64 /** 65 * Creates a TaskError object with the given message. 66 * @param message the message 67 */ 68 public TaskError(String message) { 69 super(message); 70 } 71 } 72 73 /** 74 * An enum to indicate the mode a task should use it is when executed. 75 */ 76 public enum Mode { 77 /** 78 * The task should use the interface used by the command 79 * line launcher for the task. 80 * For example, for javac: com.sun.tools.javac.Main.compile 81 */ 82 //next mode is commented out until there is a use for it 83 //CMDLINE, 84 /** 85 * The task should use a publicly defined API for the task. 86 * For example, for javac: javax.tools.JavaCompiler 87 */ 88 //next mode is commented out until there is a use for it 89 //API, 90 /** 91 * The task should use the standard launcher for the task. 92 * For example, $JAVA_HOME/bin/javac 93 */ 94 EXEC 95 } 96 97 /** 98 * An enum to indicate the expected success or failure of executing a task. 99 */ 100 public enum Expect { 101 /** It is expected that the task will complete successfully. */ 102 SUCCESS, 103 /** It is expected that the task will not complete successfully. */ 104 FAIL 105 } 106 107 /** 108 * An enum to identify the streams that may be written by a {@code Task}. 109 */ 110 public enum OutputKind { 111 /** Identifies output written to {@code System.out} or {@code stdout}. */ 112 STDOUT, 113 /** Identifies output written to {@code System.err} or {@code stderr}. */ 114 STDERR 115 /** Identifies output written to a stream provided directly to the task. */ 116 //next output kind is commented out until there is a use for it 117 //,DIRECT 118 }; 119 120 /** 121 * The results from running a {@link Task}. 122 * The results contain the exit code returned when the tool was invoked, 123 * and a map containing the output written to any streams during the 124 * execution of the tool. 125 * All tools support "stdout" and "stderr". 126 * Tools that take an explicit PrintWriter save output written to that 127 * stream as "main". 128 */ 129 public static class Result { 130 final Task task; 131 final int exitCode; 132 final Map<OutputKind, String> outputMap; 133 final List<String> command; 134 135 Result(Task task, int exitCode, Map<OutputKind, String> outputMap, 136 List<String> command) { 137 this.task = task; 138 this.exitCode = exitCode; 139 this.outputMap = outputMap; 140 this.command = command; 141 } 142 143 Result(Task task, int exitCode, Map<OutputKind, String> outputMap) { 144 this(task, exitCode, outputMap, Collections.EMPTY_LIST); 145 } 146 147 /** 148 * Returns the exit code. 149 * @return the exit code. 150 */ 151 public int getExitCode() { 152 return exitCode; 153 } 154 155 /** 156 * Returns the exit code. 157 * @return the exit code. 158 */ 159 public List<String> getCommand() { 160 return command; 161 } 162 163 /** 164 * Returns the content of a specified stream. 165 * @param outputKind the kind of the selected stream 166 * @return the content that was written to that stream when the tool 167 * was executed. 168 */ 169 public String getOutput(OutputKind outputKind) { 170 return outputMap.get(outputKind); 171 } 172 173 /** 174 * Returns the content of named streams as a list of lines. 175 * @param outputKinds the kinds of the selected streams 176 * @return the content that was written to the given streams when the tool 177 * was executed. 178 */ 179 public List<String> getOutputLines(OutputKind... outputKinds) { 180 List<String> result = new ArrayList<>(); 181 for (OutputKind outputKind : outputKinds) { 182 result.addAll(Arrays.asList(outputMap.get(outputKind).split(lineSeparator))); 183 } 184 return result; 185 } 186 187 /** 188 * Writes the content of the specified stream to the log. 189 * @param kind the kind of the selected stream 190 * @return this Result object 191 */ 192 public Result write(OutputKind kind) { 193 String text = getOutput(kind); 194 if (text == null || text.isEmpty()) 195 System.out.println("[" + task.name() + ":" + kind + "]: empty"); 196 else { 197 System.out.println("[" + task.name() + ":" + kind + "]:"); 198 System.out.print(text); 199 } 200 return this; 201 } 202 203 /** 204 * Writes the content of all streams with any content to the log. 205 * @return this Result object 206 */ 207 public Result writeAll() { 208 outputMap.forEach((name, text) -> { 209 if (!text.isEmpty()) { 210 System.out.println("[" + name + "]:"); 211 System.out.print(text); 212 } 213 }); 214 return this; 215 } 216 217 /** 218 * Verify that the specified output contains the string 219 * 220 * @param kind the output kind 221 * @param expectedString String that buffer should contain 222 * @throws RuntimeException If the string was not found 223 */ 224 public void shouldContain(OutputKind kind, String expectedString) { 225 if (!getOutput(kind).contains(expectedString)) 226 throw new RuntimeException("'" + expectedString 227 + "' missing from " + kind.name()); 228 } 229 230 /** 231 * Verify that either stdout or stderr contains the string 232 * 233 * @param expectedString String that buffer should contain 234 * @throws RuntimeException If the string was not found 235 */ 236 public void shouldContain(String expectedString) { 237 for (OutputKind kind : OutputKind.values()) { 238 if (getOutput(kind).contains(expectedString)) 239 return; 240 } 241 throw new RuntimeException("'" + expectedString 242 + "' missing from output"); 243 } 244 } 245 } 246