test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java
author herrick
Sun, 15 Sep 2019 07:34:39 -0400
branchJDK-8200758-branch
changeset 58147 45a9084fe981
parent 58113 885b0543f6e4
child 58301 e0efb29609bd
permissions -rw-r--r--
8230521: rename --output/-o option and add default value (".") Submitted-by: almatvee Reviewed-by: herrick, asemenyuk

/*
 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.jpackage.test;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Instance of PackageTest is for configuring and running a single jpackage
 * command to produce platform specific package bundle.
 *
 * Provides methods hook up custom configuration of jpackage command and
 * verification of the output bundle.
 */
public final class PackageTest {

    /**
     * Default test configuration for jpackage command. Default jpackage command
     * initialization includes:
     * <li>Set --input and --dest parameters.
     * <li>Set --name parameter. Value of the parameter is the name of the first
     * class with main function found in the callers stack. Defaults can be
     * overridden with custom initializers set with subsequent addInitializer()
     * function calls.
     */
    public PackageTest() {
        action = DEFAULT_ACTION;
        forTypes();
        setJPackageExitCode(0);
        handlers = new HashMap<>();
        currentTypes.forEach(v -> handlers.put(v, new Handler(v)));
    }

    public PackageTest forTypes(PackageType... types) {
        Collection<PackageType> newTypes;
        if (types == null || types.length == 0) {
            newTypes = PackageType.NATIVE;
        } else {
            newTypes = Set.of(types);
        }
        currentTypes = newTypes.stream().filter(type -> type.isSupported()).collect(
                Collectors.toUnmodifiableSet());
        return this;
    }

    public PackageTest forTypes(Collection<PackageType> types) {
        return forTypes(types.toArray(PackageType[]::new));
    }

    public PackageTest setJPackageExitCode(int v) {
        expectedJPackageExitCode = 0;
        return this;
    }

    public PackageTest addInitializer(Consumer<JPackageCommand> v) {
        currentTypes.stream().forEach(type -> handlers.get(type).addInitializer(
                v));
        return this;
    }

    public PackageTest addBundleVerifier(
            BiConsumer<JPackageCommand, Executor.Result> v) {
        currentTypes.stream().forEach(
                type -> handlers.get(type).addBundleVerifier(v));
        return this;
    }

    public PackageTest addBundleVerifier(Consumer<JPackageCommand> v) {
        return addBundleVerifier((cmd, unused) -> v.accept(cmd));
    }

    public PackageTest addBundlePropertyVerifier(String propertyName,
            BiConsumer<String, String> pred) {
        return addBundleVerifier(cmd -> {
            String propertyValue = null;
            switch (cmd.packageType()) {
                case LINUX_DEB:
                    propertyValue = LinuxHelper.getDebBundleProperty(
                            cmd.outputBundle(), propertyName);
                    break;

                case LINUX_RPM:
                    propertyValue = LinuxHelper.geRpmBundleProperty(
                            cmd.outputBundle(), propertyName);
                    break;

                default:
                    throw new UnsupportedOperationException();
            }

            pred.accept(propertyName, propertyValue);
        });
    }

    public PackageTest addBundlePropertyVerifier(String propertyName,
            String expectedPropertyValue) {
        return addBundlePropertyVerifier(propertyName, (unused, v) -> {
            Test.assertEquals(expectedPropertyValue, v, String.format(
                    "Check value of %s property is [%s]", propertyName, v));
        });
    }

    public PackageTest addInstallVerifier(Consumer<JPackageCommand> v) {
        currentTypes.stream().forEach(
                type -> handlers.get(type).addInstallVerifier(v));
        return this;
    }

    public PackageTest addUninstallVerifier(Consumer<JPackageCommand> v) {
        currentTypes.stream().forEach(
                type -> handlers.get(type).addUninstallVerifier(v));
        return this;
    }

    public PackageTest configureHelloApp() {
        addInitializer(cmd -> HelloApp.addTo(cmd));
        addInstallVerifier(cmd -> HelloApp.executeAndVerifyOutput(
                cmd.launcherInstallationPath(), cmd.getAllArgumentValues(
                "--arguments")));
        return this;
    }

    public void run() {
        List<Handler> supportedHandlers = handlers.values().stream()
                .filter(entry -> !entry.isVoid())
                .collect(Collectors.toList());

        if (supportedHandlers.isEmpty()) {
            // No handlers with initializers found. Nothing to do.
            return;
        }

        Supplier<JPackageCommand> initializer = new Supplier<>() {
            @Override
            public JPackageCommand get() {
                JPackageCommand cmd = new JPackageCommand().setDefaultInputOutput();
                if (bundleOutputDir != null) {
                    cmd.setArgumentValue("--dest", bundleOutputDir.toString());
                }
                cmd.setDefaultAppName();
                return cmd;
            }
        };

        supportedHandlers.forEach(handler -> handler.accept(initializer.get()));
    }

    public PackageTest setAction(Action value) {
        action = value;
        return this;
    }

    public Action getAction() {
        return action;
    }

    private class Handler implements Consumer<JPackageCommand> {

        Handler(PackageType type) {
            if (!PackageType.NATIVE.contains(type)) {
                throw new IllegalArgumentException(
                        "Attempt to configure a test for image packaging");
            }
            this.type = type;
            initializers = new ArrayList<>();
            bundleVerifiers = new ArrayList<>();
            installVerifiers = new ArrayList<>();
            uninstallVerifiers = new ArrayList<>();
        }

        boolean isVoid() {
            return initializers.isEmpty();
        }

        void addInitializer(Consumer<JPackageCommand> v) {
            initializers.add(v);
        }

        void addBundleVerifier(BiConsumer<JPackageCommand, Executor.Result> v) {
            bundleVerifiers.add(v);
        }

        void addInstallVerifier(Consumer<JPackageCommand> v) {
            installVerifiers.add(v);
        }

        void addUninstallVerifier(Consumer<JPackageCommand> v) {
            uninstallVerifiers.add(v);
        }

        @Override
        public void accept(JPackageCommand cmd) {
            type.applyTo(cmd);

            initializers.stream().forEach(v -> v.accept(cmd));
            switch (action) {
                case CREATE:
                    Executor.Result result = cmd.execute();
                    result.assertExitCodeIs(expectedJPackageExitCode);
                    Test.assertFileExists(cmd.outputBundle(),
                            expectedJPackageExitCode == 0);
                    verifyPackageBundle(JPackageCommand.createImmutable(cmd),
                            result);
                    break;

                case VERIFY_INSTALLED:
                    verifyPackageInstalled(JPackageCommand.createImmutable(cmd));
                    break;

                case VERIFY_UNINSTALLED:
                    verifyPackageUninstalled(
                            JPackageCommand.createImmutable(cmd));
                    break;
            }
        }

        private void verifyPackageBundle(JPackageCommand cmd,
                Executor.Result result) {
            bundleVerifiers.stream().forEach(v -> v.accept(cmd, result));
        }

        private void verifyPackageInstalled(JPackageCommand cmd) {
            Test.trace(String.format("Verify installed: %s",
                    cmd.getPrintableCommandLine()));
            if (cmd.isRuntime()) {
                Test.assertDirectoryExists(
                        cmd.appInstallationDirectory().resolve("runtime"), false);
                Test.assertDirectoryExists(
                        cmd.appInstallationDirectory().resolve("app"), false);
            }

            Test.assertExecutableFileExists(cmd.launcherInstallationPath(),
                    !cmd.isRuntime());

            if (PackageType.WINDOWS.contains(cmd.packageType())) {
                new WindowsHelper.AppVerifier(cmd);
            }

            installVerifiers.stream().forEach(v -> v.accept(cmd));
        }

        private void verifyPackageUninstalled(JPackageCommand cmd) {
            Test.trace(String.format("Verify uninstalled: %s",
                    cmd.getPrintableCommandLine()));
            if (!cmd.isRuntime()) {
                Test.assertFileExists(cmd.launcherInstallationPath(), false);
                Test.assertDirectoryExists(cmd.appInstallationDirectory(), false);
            }

            if (PackageType.WINDOWS.contains(cmd.packageType())) {
                new WindowsHelper.AppVerifier(cmd);
            }

            uninstallVerifiers.stream().forEach(v -> v.accept(cmd));
        }

        private final PackageType type;
        private final List<Consumer<JPackageCommand>> initializers;
        private final List<BiConsumer<JPackageCommand, Executor.Result>> bundleVerifiers;
        private final List<Consumer<JPackageCommand>> installVerifiers;
        private final List<Consumer<JPackageCommand>> uninstallVerifiers;
    }

    private Collection<PackageType> currentTypes;
    private int expectedJPackageExitCode;
    private Map<PackageType, Handler> handlers;
    private Action action;

    /**
     * Test action.
     */
    static public enum Action {
        /**
         * Create bundle.
         */
        CREATE,
        /**
         * Verify bundle installed.
         */
        VERIFY_INSTALLED,
        /**
         * Verify bundle uninstalled.
         */
        VERIFY_UNINSTALLED
    };
    private final static Action DEFAULT_ACTION;
    private final static File bundleOutputDir;

    static {
        final String JPACKAGE_TEST_OUTPUT = "jpackage.test.output";

        String val = System.getProperty(JPACKAGE_TEST_OUTPUT);
        if (val == null) {
            bundleOutputDir = null;
        } else {
            bundleOutputDir = new File(val).getAbsoluteFile();

            Test.assertTrue(bundleOutputDir.isDirectory(), String.format(
                    "Check value of %s property [%s] references a directory",
                    JPACKAGE_TEST_OUTPUT, bundleOutputDir));
            Test.assertTrue(bundleOutputDir.canWrite(), String.format(
                    "Check value of %s property [%s] references writable directory",
                    JPACKAGE_TEST_OUTPUT, bundleOutputDir));
        }
    }

    static {
        if (System.getProperty("jpackage.verify.install") != null) {
            DEFAULT_ACTION = Action.VERIFY_INSTALLED;
        } else if (System.getProperty("jpackage.verify.uninstall") != null) {
            DEFAULT_ACTION = Action.VERIFY_UNINSTALLED;
        } else {
            DEFAULT_ACTION = Action.CREATE;
        }
    }
}