test/hotspot/jtreg/applications/jcstress/TestGenerator.java
author rwestberg
Mon, 04 Jun 2018 16:21:08 +0200
changeset 50391 2bea53d7a27b
parent 50224 67066e7971e1
child 51174 bee24106cfc0
permissions -rw-r--r--
8202095: JFR TestBiasedLockRevocationEvents should cope with multiple events during a single safepoint Reviewed-by: mgronlun, egahlin

/*
 * Copyright (c) 2017, 2018, 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 applications.jcstress;

import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Calendar;
import java.util.EnumSet;
import java.util.function.Predicate;


/**
 * @notest THIS IS NOT A TEST.
 * This is a test generator, should be run only when jcstress is changed
 *
 * @library /test/lib /
 * @run main applications.jcstress.TestGenerator
 */

/**
 * Use jcstress test suite to generate jtreg tests in 'test.src' or current
 * directory. Used version is defined in JcstressRunner class.
 *
 * Each generated jtreg test file will contain several tests. Subdirectories are
 * used to allow running all tests from a file using command line. 'copy',
 * 'acqrel', 'fences', 'atomicity', 'seqcst.sync', 'seqcst.volatiles' and
 * 'other' tests will be generated.
 *
 * This generator depends on testlibrary, therefore it should be compiled and
 * added to classpath. One can replace @notest by @test in jtreg test
 * description above to run this class with jtreg.
 *
 * @see <a href=https://wiki.openjdk.java.net/display/CodeTools/jcstress>jcstress</a>
 */
public class TestGenerator {
    private static final String COPYRIGHT;
    static {
        String years;
        final int firstYear = 2017;
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        if (firstYear < currentYear) {
            years = String.format("%d, %d", firstYear, currentYear);
        } else {
            years = "" + firstYear;
        }
        COPYRIGHT = String.format("/*\n" +
                " * Copyright (c) %s, Oracle and/or its affiliates. All rights reserved.\n" +
                " * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" +
                " *\n" +
                " * This code is free software; you can redistribute it and/or modify it\n" +
                " * under the terms of the GNU General Public License version 2 only, as\n" +
                " * published by the Free Software Foundation.\n" +
                " *\n" +
                " * This code is distributed in the hope that it will be useful, but WITHOUT\n" +
                " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" +
                " * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n" +
                " * version 2 for more details (a copy is included in the LICENSE file that\n" +
                " * accompanied this code).\n" +
                " *\n" +
                " * You should have received a copy of the GNU General Public License version\n" +
                " * 2 along with this work; if not, write to the Free Software Foundation,\n" +
                " * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" +
                " *\n" +
                " * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n" +
                " * or visit www.oracle.com if you need additional information or have any\n" +
                " * questions.\n" +
                " */\n\n", years);
    }

    private static enum JcstressGroup {
        MEMEFFECTS("memeffects"),
        COPY("copy"),
        ACQREL("acqrel"),
        FENCES("fences"),
        ATOMICITY("atomicity"),
        SEQCST_SYNC("seqcst.sync"),
        SEQCST_VOLATILES("seqcst.volatiles"),
        OTHER("other", JcstressGroup.otherFilter());

        private final String groupName;
        private final Predicate<String> filter;

        private JcstressGroup(String groupName, Predicate<String> filter) {
            this.groupName = groupName;
            this.filter = filter;
        }

        private JcstressGroup(String groupName) {
            this(groupName, JcstressGroup.nameFilter(groupName));
        }

        private static Predicate<String> nameFilter(String group) {
            return s -> s.startsWith("org.openjdk.jcstress.tests." + group + ".");
        }

        private static Predicate<String> otherFilter() {
            return (s) -> {
                for (JcstressGroup g : EnumSet.complementOf(EnumSet.of(OTHER))) {
                    if (g.filter.test(s)) {
                        return false;
                    }
                }
                return true;
            };
        }
    }

    public static String DESC_FORMAT = "\n"
            + "/**\n"
            + " * @test %1$s\n"
            + " * @library /test/lib /\n"
            + " * @run driver/timeout=2400 " + JcstressRunner.class.getName()
                    // verbose output
                    + " -v"
                    // test mode preset
                    + " -m default"
                    // test name
                    + " -t %1$s\n"
            + " */\n";

    public static void main(String[] args)  {
        Path path = JcstressRunner.pathToArtifact();
        Path output;
        try {
            output = Files.createTempFile("jcstress", ".out");
            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
                    "-jar",
                    path.toAbsolutePath().toString(),
                    "-l");
            pb.redirectOutput(output.toFile());
            new OutputAnalyzer(pb.start()).shouldHaveExitValue(0);
        } catch (Exception e) {
            throw new Error("Can not get list of tests", e);
        }
        for (JcstressGroup group : JcstressGroup.values()) {
            try {
                try (BufferedReader reader = Files.newBufferedReader(output)) {
                    // skip first 4 lines: name, -{80}, revision and empty line
                    for (int i = 0; i < 4; ++i) {
                        reader.readLine();
                    }
                    new TestGenerator(group).generate(reader);
                }
            } catch (IOException e) {
                throw new Error("Generating tests for " + group.name()
                                + " has failed", e);
            }
        }
        output.toFile().delete();
    }

    private final JcstressGroup group;

    private TestGenerator(JcstressGroup group) {
        this.group = group;
    }

    private void generate(BufferedReader reader) throws IOException {
        // array is needed to change value inside a lambda
        long[] count = {0L};
        String root = Utils.TEST_SRC;
        Path testFile = Paths.get(root)
                             .resolve(group.groupName)
                             .resolve("Test.java");
        File testDir = testFile.getParent().toFile();
        if (!testDir.mkdirs() && !testDir.exists()) {
            throw new Error("Can not create directories for "
                            + testFile.toString());
        }

        try (PrintStream ps = new PrintStream(testFile.toFile())) {
            ps.print(COPYRIGHT);
            ps.printf("/* DO NOT MODIFY THIS FILE. GENERATED BY %s */\n",
                      getClass().getName());

            reader.lines()
                  .filter(group.filter)
                  .forEach(s -> {
                      count[0]++;
                      ps.printf(DESC_FORMAT, s);
                  });
            ps.print('\n');
        }
        System.out.printf("%d tests generated in %s%n",
                count[0], group.groupName);
    }
}