1 /* 2 * Copyright (c) 2019, 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 package jdk.jpackage.test; 24 25 import java.io.File; 26 import java.nio.file.Path; 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Set; 33 import java.util.function.BiConsumer; 34 import java.util.function.Consumer; 35 import java.util.function.Supplier; 36 import java.util.stream.Collectors; 37 import java.util.stream.Stream; 38 39 /** 40 * Instance of PackageTest is for configuring and running a single jpackage 41 * command to produce platform specific package bundle. 42 * 43 * Provides methods hook up custom configuration of jpackage command and 44 * verification of the output bundle. 45 */ 46 public final class PackageTest { 47 48 /** 49 * Default test configuration for jpackage command. Default jpackage command 50 * initialization includes: 51 * <li>Set --input and --dest parameters. 52 * <li>Set --name parameter. Value of the parameter is the name of the first 53 * class with main function found in the callers stack. Defaults can be 54 * overridden with custom initializers set with subsequent addInitializer() 55 * function calls. 56 */ 57 public PackageTest() { 58 action = DEFAULT_ACTION; 59 forTypes(); 60 setJPackageExitCode(0); 61 handlers = new HashMap<>(); 62 currentTypes.forEach(v -> handlers.put(v, new Handler(v))); 63 } 64 65 public PackageTest forTypes(PackageType... types) { 66 Collection<PackageType> newTypes; 67 if (types == null || types.length == 0) { 68 newTypes = PackageType.NATIVE; 69 } else { 70 newTypes = Set.of(types); 71 } 72 currentTypes = newTypes.stream().filter(type -> type.isSupported()).collect( 73 Collectors.toUnmodifiableSet()); 74 return this; 75 } 76 77 public PackageTest forTypes(Collection<PackageType> types) { 78 return forTypes(types.toArray(PackageType[]::new)); 79 } 80 81 public PackageTest setJPackageExitCode(int v) { 82 expectedJPackageExitCode = 0; 83 return this; 84 } 85 86 public PackageTest addInitializer(Consumer<JPackageCommand> v) { 87 currentTypes.stream().forEach(type -> handlers.get(type).addInitializer( 88 v)); 89 return this; 90 } 91 92 public PackageTest addBundleVerifier( 93 BiConsumer<JPackageCommand, Executor.Result> v) { 94 currentTypes.stream().forEach( 95 type -> handlers.get(type).addBundleVerifier(v)); 96 return this; 97 } 98 99 public PackageTest addBundleVerifier(Consumer<JPackageCommand> v) { 100 return addBundleVerifier((cmd, unused) -> v.accept(cmd)); 101 } 102 103 public PackageTest addBundlePropertyVerifier(String propertyName, 104 BiConsumer<String, String> pred) { 105 return addBundleVerifier(cmd -> { 106 String propertyValue = null; 107 switch (cmd.packageType()) { 108 case LINUX_DEB: 109 propertyValue = LinuxHelper.getDebBundleProperty( 110 cmd.outputBundle(), propertyName); 111 break; 112 113 case LINUX_RPM: 114 propertyValue = LinuxHelper.geRpmBundleProperty( 115 cmd.outputBundle(), propertyName); 116 break; 117 118 default: 119 throw new UnsupportedOperationException(); 120 } 121 122 pred.accept(propertyName, propertyValue); 123 }); 124 } 125 126 public PackageTest addBundlePropertyVerifier(String propertyName, 127 String expectedPropertyValue) { 128 return addBundlePropertyVerifier(propertyName, (unused, v) -> { 129 Test.assertEquals(expectedPropertyValue, v, String.format( 130 "Check value of %s property is [%s]", propertyName, v)); 131 }); 132 } 133 134 public PackageTest addInstallVerifier(Consumer<JPackageCommand> v) { 135 currentTypes.stream().forEach( 136 type -> handlers.get(type).addInstallVerifier(v)); 137 return this; 138 } 139 140 public PackageTest addUninstallVerifier(Consumer<JPackageCommand> v) { 141 currentTypes.stream().forEach( 142 type -> handlers.get(type).addUninstallVerifier(v)); 143 return this; 144 } 145 146 public PackageTest configureHelloApp() { 147 addInitializer(cmd -> HelloApp.addTo(cmd)); 148 addInstallVerifier(cmd -> HelloApp.executeAndVerifyOutput( 149 cmd.launcherInstallationPath(), cmd.getAllArgumentValues( 150 "--arguments"))); 151 return this; 152 } 153 154 public void run() { 155 List<Handler> supportedHandlers = handlers.values().stream() 156 .filter(entry -> !entry.isVoid()) 157 .collect(Collectors.toList()); 158 159 if (supportedHandlers.isEmpty()) { 160 // No handlers with initializers found. Nothing to do. 161 return; 162 } 163 164 Supplier<JPackageCommand> initializer = new Supplier<>() { 165 @Override 166 public JPackageCommand get() { 167 JPackageCommand cmd = new JPackageCommand().setDefaultInputOutput(); 168 if (bundleOutputDir != null) { 169 cmd.setArgumentValue("--dest", bundleOutputDir.toString()); 170 } 171 cmd.setDefaultAppName(); 172 return cmd; 173 } 174 }; 175 176 supportedHandlers.forEach(handler -> handler.accept(initializer.get())); 177 } 178 179 public PackageTest setAction(Action value) { 180 action = value; 181 return this; 182 } 183 184 public Action getAction() { 185 return action; 186 } 187 188 private class Handler implements Consumer<JPackageCommand> { 189 190 Handler(PackageType type) { 191 if (!PackageType.NATIVE.contains(type)) { 192 throw new IllegalArgumentException( 193 "Attempt to configure a test for image packaging"); 194 } 195 this.type = type; 196 initializers = new ArrayList<>(); 197 bundleVerifiers = new ArrayList<>(); 198 installVerifiers = new ArrayList<>(); 199 uninstallVerifiers = new ArrayList<>(); 200 } 201 202 boolean isVoid() { 203 return initializers.isEmpty(); 204 } 205 206 void addInitializer(Consumer<JPackageCommand> v) { 207 initializers.add(v); 208 } 209 210 void addBundleVerifier(BiConsumer<JPackageCommand, Executor.Result> v) { 211 bundleVerifiers.add(v); 212 } 213 214 void addInstallVerifier(Consumer<JPackageCommand> v) { 215 installVerifiers.add(v); 216 } 217 218 void addUninstallVerifier(Consumer<JPackageCommand> v) { 219 uninstallVerifiers.add(v); 220 } 221 222 @Override 223 public void accept(JPackageCommand cmd) { 224 type.applyTo(cmd); 225 226 initializers.stream().forEach(v -> v.accept(cmd)); 227 switch (action) { 228 case CREATE: 229 Executor.Result result = cmd.execute(); 230 result.assertExitCodeIs(expectedJPackageExitCode); 231 Test.assertFileExists(cmd.outputBundle(), 232 expectedJPackageExitCode == 0); 233 verifyPackageBundle(JPackageCommand.createImmutable(cmd), 234 result); 235 break; 236 237 case VERIFY_INSTALLED: 238 verifyPackageInstalled(JPackageCommand.createImmutable(cmd)); 239 break; 240 241 case VERIFY_UNINSTALLED: 242 verifyPackageUninstalled( 243 JPackageCommand.createImmutable(cmd)); 244 break; 245 } 246 } 247 248 private void verifyPackageBundle(JPackageCommand cmd, 249 Executor.Result result) { 250 bundleVerifiers.stream().forEach(v -> v.accept(cmd, result)); 251 } 252 253 private void verifyPackageInstalled(JPackageCommand cmd) { 254 Test.trace(String.format("Verify installed: %s", 255 cmd.getPrintableCommandLine())); 256 if (cmd.isRuntime()) { 257 Test.assertDirectoryExists( 258 cmd.appInstallationDirectory().resolve("runtime"), false); 259 Test.assertDirectoryExists( 260 cmd.appInstallationDirectory().resolve("app"), false); 261 } 262 263 Test.assertExecutableFileExists(cmd.launcherInstallationPath(), 264 !cmd.isRuntime()); 265 266 if (PackageType.WINDOWS.contains(cmd.packageType())) { 267 new WindowsHelper.AppVerifier(cmd); 268 } 269 270 installVerifiers.stream().forEach(v -> v.accept(cmd)); 271 } 272 273 private void verifyPackageUninstalled(JPackageCommand cmd) { 274 Test.trace(String.format("Verify uninstalled: %s", 275 cmd.getPrintableCommandLine())); 276 if (!cmd.isRuntime()) { 277 Test.assertFileExists(cmd.launcherInstallationPath(), false); 278 Test.assertDirectoryExists(cmd.appInstallationDirectory(), false); 279 } 280 281 if (PackageType.WINDOWS.contains(cmd.packageType())) { 282 new WindowsHelper.AppVerifier(cmd); 283 } 284 285 uninstallVerifiers.stream().forEach(v -> v.accept(cmd)); 286 } 287 288 private final PackageType type; 289 private final List<Consumer<JPackageCommand>> initializers; 290 private final List<BiConsumer<JPackageCommand, Executor.Result>> bundleVerifiers; 291 private final List<Consumer<JPackageCommand>> installVerifiers; 292 private final List<Consumer<JPackageCommand>> uninstallVerifiers; 293 } 294 295 private Collection<PackageType> currentTypes; 296 private int expectedJPackageExitCode; 297 private Map<PackageType, Handler> handlers; 298 private Action action; 299 300 /** 301 * Test action. 302 */ 303 static public enum Action { 304 /** 305 * Create bundle. 306 */ 307 CREATE, 308 /** 309 * Verify bundle installed. 310 */ 311 VERIFY_INSTALLED, 312 /** 313 * Verify bundle uninstalled. 314 */ 315 VERIFY_UNINSTALLED 316 }; 317 private final static Action DEFAULT_ACTION; 318 private final static File bundleOutputDir; 319 320 static { 321 final String JPACKAGE_TEST_OUTPUT = "jpackage.test.output"; 322 323 String val = System.getProperty(JPACKAGE_TEST_OUTPUT); 324 if (val == null) { 325 bundleOutputDir = null; 326 } else { 327 bundleOutputDir = new File(val).getAbsoluteFile(); 328 329 Test.assertTrue(bundleOutputDir.isDirectory(), String.format( 330 "Check value of %s property [%s] references a directory", 331 JPACKAGE_TEST_OUTPUT, bundleOutputDir)); 332 Test.assertTrue(bundleOutputDir.canWrite(), String.format( 333 "Check value of %s property [%s] references writable directory", 334 JPACKAGE_TEST_OUTPUT, bundleOutputDir)); 335 } 336 } 337 338 static { 339 if (System.getProperty("jpackage.verify.install") != null) { 340 DEFAULT_ACTION = Action.VERIFY_INSTALLED; 341 } else if (System.getProperty("jpackage.verify.uninstall") != null) { 342 DEFAULT_ACTION = Action.VERIFY_UNINSTALLED; 343 } else { 344 DEFAULT_ACTION = Action.CREATE; 345 } 346 } 347 }