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 package jdk.jpackage.test; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.nio.file.Files; 28 import java.nio.file.Path; 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.concurrent.atomic.AtomicBoolean; 32 import java.util.regex.Matcher; 33 import java.util.regex.Pattern; 34 import java.util.stream.Collectors; 35 import jdk.jpackage.test.Functional.ThrowingFunction; 36 import jdk.jpackage.test.Functional.ThrowingSupplier; 37 38 public class HelloApp { 39 40 HelloApp(JavaAppDesc appDesc) { 41 if (appDesc == null) { 42 this.appDesc = createDefaltAppDesc(); 43 } else { 44 this.appDesc = appDesc; 45 } 46 } 47 48 private JarBuilder prepareSources(Path srcDir) throws IOException { 49 final String qualifiedClassName = appDesc.className(); 50 51 final String className = qualifiedClassName.substring( 52 qualifiedClassName.lastIndexOf('.') + 1); 53 final String packageName = appDesc.packageName(); 54 55 final Path srcFile = srcDir.resolve(Path.of(String.join( 56 File.separator, qualifiedClassName.split("\\.")) + ".java")); 57 Files.createDirectories(srcFile.getParent()); 58 114 private JarBuilder createJarBuilder() { 115 JarBuilder builder = new JarBuilder(); 116 if (appDesc.jarWithMainClass()) { 117 builder.setMainClass(appDesc.className()); 118 } 119 return builder; 120 } 121 122 void addTo(JPackageCommand cmd) { 123 final String moduleName = appDesc.moduleName(); 124 final String jarFileName = appDesc.jarFileName(); 125 final String qualifiedClassName = appDesc.className(); 126 127 if (moduleName != null && appDesc.packageName() == null) { 128 throw new IllegalArgumentException(String.format( 129 "Module [%s] with default package", moduleName)); 130 } 131 132 if (moduleName == null && CLASS_NAME.equals(qualifiedClassName)) { 133 // Use Hello.java as is. 134 cmd.addAction((self) -> { 135 Path jarFile = self.inputDir().resolve(jarFileName); 136 createJarBuilder().setOutputJar(jarFile).addSourceFile( 137 HELLO_JAVA).create(); 138 }); 139 } else { 140 cmd.addAction((self) -> { 141 final Path jarFile; 142 if (moduleName == null) { 143 jarFile = self.inputDir().resolve(jarFileName); 144 } else { 145 // `--module-path` option should be set by the moment 146 // when this action is being executed. 147 jarFile = Path.of(self.getArgumentValue("--module-path", 148 () -> self.inputDir().toString()), jarFileName); 149 Files.createDirectories(jarFile.getParent()); 150 } 151 152 TKit.withTempDirectory("src", 153 workDir -> prepareSources(workDir).setOutputJar(jarFile).create()); 154 }); 155 } 156 157 if (moduleName == null) { 158 cmd.addArguments("--main-jar", jarFileName); 159 cmd.addArguments("--main-class", qualifiedClassName); 160 } else { 161 cmd.addArguments("--module-path", TKit.workDir().resolve( 162 "input-modules")); 163 cmd.addArguments("--module", String.join("/", moduleName, 164 qualifiedClassName)); 165 // For modular app assume nothing will go in input directory and thus 166 // nobody will create input directory, so remove corresponding option 167 // from jpackage command line. 168 cmd.removeArgumentWithValue("--input"); 169 } 170 if (TKit.isWindows()) { 171 cmd.addArguments("--win-console"); 172 } 173 } 174 175 static JavaAppDesc createDefaltAppDesc() { 176 return new JavaAppDesc().setClassName(CLASS_NAME).setJarFileName( 177 "hello.jar"); 178 } 179 180 static void verifyOutputFile(Path outputFile, List<String> args) { 181 if (!outputFile.isAbsolute()) { 182 verifyOutputFile(outputFile.toAbsolutePath().normalize(), args); 183 return; 184 } 185 186 TKit.assertFileExists(outputFile); 187 188 List<String> contents = ThrowingSupplier.toSupplier( 189 () -> Files.readAllLines(outputFile)).get(); 190 191 List<String> expected = new ArrayList<>(List.of( 192 "jpackage test application", 193 String.format("args.length: %d", args.size()) 194 )); 195 expected.addAll(args); 196 197 TKit.assertStringListEquals(expected, contents, String.format( 198 "Check contents of [%s] file", outputFile)); 199 } 200 201 public static void executeLauncherAndVerifyOutput(JPackageCommand cmd) { 202 final Path launcherPath = cmd.appLauncherPath(); 203 if (!cmd.isFakeRuntime(String.format("Not running [%s] launcher", 204 launcherPath))) { 205 executeAndVerifyOutput(launcherPath, cmd.getAllArgumentValues( 206 "--arguments")); 207 } 208 } 209 210 public static void executeAndVerifyOutput(Path helloAppLauncher, 211 String... defaultLauncherArgs) { 212 executeAndVerifyOutput(helloAppLauncher, List.of(defaultLauncherArgs)); 213 } 214 215 public static void executeAndVerifyOutput(Path helloAppLauncher, 216 List<String> defaultLauncherArgs) { 217 // Output file will be created in the current directory. 218 Path outputFile = TKit.workDir().resolve(OUTPUT_FILENAME); 219 ThrowingFunction.toFunction(Files::deleteIfExists).apply(outputFile); 220 new Executor() 221 .setDirectory(outputFile.getParent()) 222 .setExecutable(helloAppLauncher) 223 .dumpOutput() 224 .execute() 225 .assertExitCodeIsZero(); 226 227 verifyOutputFile(outputFile, defaultLauncherArgs); 228 } 229 230 final static String OUTPUT_FILENAME = "appOutput.txt"; 231 232 private final JavaAppDesc appDesc; 233 234 private static final Path HELLO_JAVA = TKit.TEST_SRC_ROOT.resolve( 235 "apps/image/Hello.java"); 236 237 private final static String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( 238 "\\.", 2)[0]; 239 } | 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 package jdk.jpackage.test; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.nio.file.Files; 28 import java.nio.file.Path; 29 import java.util.*; 30 import java.util.concurrent.atomic.AtomicBoolean; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 import java.util.stream.Collectors; 34 import java.util.stream.Stream; 35 import jdk.jpackage.test.Functional.ThrowingFunction; 36 import jdk.jpackage.test.Functional.ThrowingSupplier; 37 38 public final class HelloApp { 39 40 HelloApp(JavaAppDesc appDesc) { 41 if (appDesc == null) { 42 this.appDesc = createDefaltAppDesc(); 43 } else { 44 this.appDesc = appDesc; 45 } 46 } 47 48 private JarBuilder prepareSources(Path srcDir) throws IOException { 49 final String qualifiedClassName = appDesc.className(); 50 51 final String className = qualifiedClassName.substring( 52 qualifiedClassName.lastIndexOf('.') + 1); 53 final String packageName = appDesc.packageName(); 54 55 final Path srcFile = srcDir.resolve(Path.of(String.join( 56 File.separator, qualifiedClassName.split("\\.")) + ".java")); 57 Files.createDirectories(srcFile.getParent()); 58 114 private JarBuilder createJarBuilder() { 115 JarBuilder builder = new JarBuilder(); 116 if (appDesc.jarWithMainClass()) { 117 builder.setMainClass(appDesc.className()); 118 } 119 return builder; 120 } 121 122 void addTo(JPackageCommand cmd) { 123 final String moduleName = appDesc.moduleName(); 124 final String jarFileName = appDesc.jarFileName(); 125 final String qualifiedClassName = appDesc.className(); 126 127 if (moduleName != null && appDesc.packageName() == null) { 128 throw new IllegalArgumentException(String.format( 129 "Module [%s] with default package", moduleName)); 130 } 131 132 if (moduleName == null && CLASS_NAME.equals(qualifiedClassName)) { 133 // Use Hello.java as is. 134 cmd.addPrerequisiteAction((self) -> { 135 Path jarFile = self.inputDir().resolve(jarFileName); 136 createJarBuilder().setOutputJar(jarFile).addSourceFile( 137 HELLO_JAVA).create(); 138 }); 139 } else { 140 cmd.addPrerequisiteAction((self) -> { 141 final Path jarFile; 142 if (moduleName == null) { 143 jarFile = self.inputDir().resolve(jarFileName); 144 } else { 145 // `--module-path` option should be set by the moment 146 // when this action is being executed. 147 jarFile = Path.of(self.getArgumentValue("--module-path", 148 () -> self.inputDir().toString()), jarFileName); 149 Files.createDirectories(jarFile.getParent()); 150 } 151 152 TKit.withTempDirectory("src", 153 workDir -> prepareSources(workDir).setOutputJar(jarFile).create()); 154 }); 155 } 156 157 if (moduleName == null) { 158 cmd.addArguments("--main-jar", jarFileName); 159 cmd.addArguments("--main-class", qualifiedClassName); 160 } else { 161 cmd.addArguments("--module-path", TKit.workDir().resolve( 162 "input-modules")); 163 cmd.addArguments("--module", String.join("/", moduleName, 164 qualifiedClassName)); 165 // For modular app assume nothing will go in input directory and thus 166 // nobody will create input directory, so remove corresponding option 167 // from jpackage command line. 168 cmd.removeArgumentWithValue("--input"); 169 } 170 if (TKit.isWindows()) { 171 cmd.addArguments("--win-console"); 172 } 173 } 174 175 static JavaAppDesc createDefaltAppDesc() { 176 return new JavaAppDesc().setClassName(CLASS_NAME).setJarFileName( 177 "hello.jar"); 178 } 179 180 static void verifyOutputFile(Path outputFile, List<String> args, 181 Map<String, String> params) { 182 if (!outputFile.isAbsolute()) { 183 verifyOutputFile(outputFile.toAbsolutePath().normalize(), args, 184 params); 185 return; 186 } 187 188 TKit.assertFileExists(outputFile); 189 190 List<String> contents = ThrowingSupplier.toSupplier( 191 () -> Files.readAllLines(outputFile)).get(); 192 193 List<String> expected = new ArrayList<>(List.of( 194 "jpackage test application", 195 String.format("args.length: %d", args.size()) 196 )); 197 expected.addAll(args); 198 expected.addAll(params.entrySet().stream() 199 .sorted(Comparator.comparing(Map.Entry::getKey)) 200 .map(entry -> String.format("-D%s=%s", entry.getKey(), 201 entry.getValue())) 202 .collect(Collectors.toList())); 203 204 TKit.assertStringListEquals(expected, contents, String.format( 205 "Check contents of [%s] file", outputFile)); 206 } 207 208 public static void executeLauncherAndVerifyOutput(JPackageCommand cmd, 209 String... args) { 210 final Path launcherPath = cmd.appLauncherPath(); 211 if (cmd.isFakeRuntime(String.format("Not running [%s] launcher", 212 launcherPath))) { 213 return; 214 } 215 216 assertApp(launcherPath) 217 .addDefaultArguments(Optional 218 .ofNullable(cmd.getAllArgumentValues("--arguments")) 219 .orElseGet(() -> new String[0])) 220 .addJavaOptions(Optional 221 .ofNullable(cmd.getAllArgumentValues("--java-options")) 222 .orElseGet(() -> new String[0])) 223 .executeAndVerifyOutput(args); 224 } 225 226 public final static class AppOutputVerifier { 227 AppOutputVerifier(Path helloAppLauncher) { 228 this.launcherPath = helloAppLauncher; 229 this.params = new HashMap<>(); 230 this.defaultLauncherArgs = new ArrayList<>(); 231 } 232 233 public AppOutputVerifier addDefaultArguments(String... v) { 234 return addDefaultArguments(List.of(v)); 235 } 236 237 public AppOutputVerifier addDefaultArguments(Collection<String> v) { 238 defaultLauncherArgs.addAll(v); 239 return this; 240 } 241 242 public AppOutputVerifier addParam(String name, String value) { 243 if (name.startsWith("param")) { 244 params.put(name, value); 245 } 246 return this; 247 } 248 249 public AppOutputVerifier addParams(Collection<Map.Entry<String, String>> v) { 250 v.forEach(entry -> addParam(entry.getKey(), entry.getValue())); 251 return this; 252 } 253 public AppOutputVerifier addParams(Map<String, String> v) { 254 return addParams(v.entrySet()); 255 } 256 257 public AppOutputVerifier addParams(Map.Entry<String, String>... v) { 258 return addParams(List.of(v)); 259 } 260 261 public AppOutputVerifier addJavaOptions(String... v) { 262 return addJavaOptions(List.of(v)); 263 } 264 265 public AppOutputVerifier addJavaOptions(Collection<String> v) { 266 return addParams(v.stream() 267 .filter(javaOpt -> javaOpt.startsWith("-D")) 268 .map(javaOpt -> { 269 var components = javaOpt.split("=", 2); 270 return Map.entry(components[0].substring(2), components[1]); 271 }) 272 .collect(Collectors.toList())); 273 } 274 275 public void executeAndVerifyOutput(String... args) { 276 // Output file will be created in the current directory. 277 Path outputFile = TKit.workDir().resolve(OUTPUT_FILENAME); 278 ThrowingFunction.toFunction(Files::deleteIfExists).apply(outputFile); 279 280 final Path executablePath; 281 if (launcherPath.isAbsolute()) { 282 executablePath = launcherPath; 283 } else { 284 // Make sure path to executable is relative to the current directory. 285 executablePath = Path.of(".").resolve(launcherPath.normalize()); 286 } 287 288 final List<String> launcherArgs = List.of(args); 289 new Executor() 290 .setDirectory(outputFile.getParent()) 291 .setExecutable(executablePath) 292 .addArguments(launcherArgs) 293 .dumpOutput() 294 .execute(); 295 296 final List<String> appArgs; 297 if (launcherArgs.isEmpty()) { 298 appArgs = defaultLauncherArgs; 299 } else { 300 appArgs = launcherArgs; 301 } 302 303 verifyOutputFile(outputFile, appArgs, params); 304 } 305 306 private final Path launcherPath; 307 private final List<String> defaultLauncherArgs; 308 private final Map<String, String> params; 309 } 310 311 public static AppOutputVerifier assertApp(Path helloAppLauncher) { 312 return new AppOutputVerifier(helloAppLauncher); 313 } 314 315 final static String OUTPUT_FILENAME = "appOutput.txt"; 316 317 private final JavaAppDesc appDesc; 318 319 private static final Path HELLO_JAVA = TKit.TEST_SRC_ROOT.resolve( 320 "apps/image/Hello.java"); 321 322 private final static String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( 323 "\\.", 2)[0]; 324 } |