1 /*
   2  * Copyright (c) 2013, 2015, 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 /*
  25  * @test
  26  * @bug 8023524
  27  * @summary tests logging generated classes for lambda
  28  * @library /java/nio/file
  29  * @modules jdk.compiler
  30  * @run testng LogGeneratedClassesTest
  31  */
  32 import java.io.File;
  33 import java.io.IOException;
  34 import java.util.ArrayList;
  35 import java.util.List;
  36 import java.util.function.Predicate;
  37 import java.nio.file.Files;
  38 import java.nio.file.Path;
  39 import java.nio.file.Paths;
  40 import java.nio.file.attribute.PosixFileAttributeView;
  41 
  42 import org.testng.annotations.AfterClass;
  43 import org.testng.annotations.BeforeClass;
  44 import org.testng.annotations.Test;
  45 import org.testng.SkipException;
  46 
  47 import static java.nio.file.attribute.PosixFilePermissions.*;
  48 import static org.testng.Assert.assertEquals;
  49 import static org.testng.Assert.assertFalse;
  50 import static org.testng.Assert.assertTrue;
  51 
  52 public class LogGeneratedClassesTest extends LUtils {
  53     String longFQCN;
  54 
  55     @BeforeClass
  56     public void setup() throws IOException {
  57         final List<String> scratch = new ArrayList<>();
  58         scratch.clear();
  59         scratch.add("package com.example;");
  60         scratch.add("public class TestLambda {");
  61         scratch.add("    interface I {");
  62         scratch.add("        int foo();");
  63         scratch.add("    }");
  64         scratch.add("    public static void main(String[] args) {");
  65         scratch.add("        I lam = () -> 10;");
  66         scratch.add("        Runnable r = () -> {");
  67         scratch.add("            System.out.println(\"Runnable\");");
  68         scratch.add("        };");
  69         scratch.add("        r.run();");
  70         scratch.add("        System.out.println(\"Finish\");");
  71         scratch.add("    }");
  72         scratch.add("}");
  73 
  74         File test = new File("TestLambda.java");
  75         createFile(test, scratch);
  76         compile("-d", ".", test.getName());
  77 
  78         scratch.remove(0);
  79         scratch.remove(0);
  80         scratch.add(0, "public class LongPackageName {");
  81         StringBuilder sb = new StringBuilder("com.example.");
  82         // longer than 255 which exceed max length of most filesystems
  83         for (int i = 0; i < 30; i++) {
  84             sb.append("nonsense.");
  85         }
  86         sb.append("enough");
  87         longFQCN = sb.toString() + ".LongPackageName";
  88         sb.append(";");
  89         sb.insert(0, "package ");
  90         scratch.add(0, sb.toString());
  91         test = new File("LongPackageName.java");
  92         createFile(test, scratch);
  93         compile("-d", ".", test.getName());
  94 
  95         // create target
  96         Files.createDirectory(Paths.get("dump"));
  97         Files.createDirectories(Paths.get("dumpLong/com/example/nonsense"));
  98         Files.createFile(Paths.get("dumpLong/com/example/nonsense/nonsense"));
  99         Files.createFile(Paths.get("file"));
 100     }
 101 
 102     @AfterClass
 103     public void cleanup() throws IOException {
 104         Files.delete(Paths.get("TestLambda.java"));
 105         Files.delete(Paths.get("LongPackageName.java"));
 106         Files.delete(Paths.get("file"));
 107         TestUtil.removeAll(Paths.get("com"));
 108         TestUtil.removeAll(Paths.get("dump"));
 109         TestUtil.removeAll(Paths.get("dumpLong"));
 110     }
 111 
 112     @Test
 113     public void testNotLogging() {
 114         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 115                                "-cp", ".",
 116                                "-Djava.security.manager",
 117                                "com.example.TestLambda");
 118         tr.assertZero("Should still return 0");
 119     }
 120 
 121     @Test
 122     public void testLogging() throws IOException {
 123         assertTrue(Files.exists(Paths.get("dump")));
 124         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 125                                "-cp", ".",
 126                                "-Djdk.internal.lambda.dumpProxyClasses=dump",
 127                                "-Djava.security.manager",
 128                                "com.example.TestLambda");
 129         // dump/com/example + 2 class files
 130         assertEquals(Files.walk(Paths.get("dump")).count(), 5, "Two lambda captured");
 131         tr.assertZero("Should still return 0");
 132     }
 133 
 134     @Test
 135     public void testDumpDirNotExist() throws IOException {
 136         assertFalse(Files.exists(Paths.get("notExist")));
 137         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 138                                "-cp", ".",
 139                                "-Djdk.internal.lambda.dumpProxyClasses=notExist",
 140                                "-Djava.security.manager",
 141                                "com.example.TestLambda");
 142         assertEquals(tr.testOutput.stream()
 143                                   .filter(s -> s.startsWith("WARNING"))
 144                                   .peek(s -> assertTrue(s.contains("does not exist")))
 145                                   .count(),
 146                      1, "only show error once");
 147         tr.assertZero("Should still return 0");
 148     }
 149 
 150     @Test
 151     public void testDumpDirIsFile() throws IOException {
 152         assertTrue(Files.isRegularFile(Paths.get("file")));
 153         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 154                                "-cp", ".",
 155                                "-Djdk.internal.lambda.dumpProxyClasses=file",
 156                                "-Djava.security.manager",
 157                                "com.example.TestLambda");
 158         assertEquals(tr.testOutput.stream()
 159                                   .filter(s -> s.startsWith("WARNING"))
 160                                   .peek(s -> assertTrue(s.contains("not a directory")))
 161                                   .count(),
 162                      1, "only show error once");
 163         tr.assertZero("Should still return 0");
 164     }
 165 
 166     private static boolean isWriteableDirectory(Path p) {
 167         if (!Files.isDirectory(p)) {
 168             return false;
 169         }
 170         Path test = p.resolve(Paths.get("test"));
 171         try {
 172             Files.createFile(test);
 173             assertTrue(Files.exists(test));
 174             return true;
 175         } catch (IOException e) {
 176             assertFalse(Files.exists(test));
 177             return false;
 178         } finally {
 179             if (Files.exists(test)) {
 180                 try {
 181                     Files.delete(test);
 182                 } catch (IOException e) {
 183                     throw new Error(e);
 184                 }
 185             }
 186         }
 187     }
 188 
 189     @Test
 190     public void testDumpDirNotWritable() throws IOException {
 191         if (!Files.getFileStore(Paths.get("."))
 192                   .supportsFileAttributeView(PosixFileAttributeView.class)) {
 193             // No easy way to setup readonly directory without POSIX
 194             // We would like to skip the test with a cause with
 195             //     throw new SkipException("Posix not supported");
 196             // but jtreg will report failure so we just pass the test
 197             // which we can look at if jtreg changed its behavior
 198             System.out.println("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test.");
 199             return;
 200         }
 201 
 202         Files.createDirectory(Paths.get("readOnly"),
 203                               asFileAttribute(fromString("r-xr-xr-x")));
 204         try {
 205             if (isWriteableDirectory(Paths.get("readOnly"))) {
 206                 // Skipping the test: it's allowed to write into read-only directory
 207                 // (e.g. current user is super user).
 208                 System.out.println("WARNING: readOnly directory is writeable. Skipping testDumpDirNotWritable test.");
 209                 return;
 210             }
 211 
 212             TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 213                                    "-cp", ".",
 214                                    "-Djdk.internal.lambda.dumpProxyClasses=readOnly",
 215                                    "-Djava.security.manager",
 216                                    "com.example.TestLambda");
 217             assertEquals(tr.testOutput.stream()
 218                                       .filter(s -> s.startsWith("WARNING"))
 219                                       .peek(s -> assertTrue(s.contains("not writable")))
 220                                       .count(),
 221                          1, "only show error once");
 222             tr.assertZero("Should still return 0");
 223         } finally {
 224             TestUtil.removeAll(Paths.get("readOnly"));
 225         }
 226     }
 227 
 228     @Test
 229     public void testLoggingException() throws IOException {
 230         assertTrue(Files.exists(Paths.get("dumpLong")));
 231         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
 232                                "-cp", ".",
 233                                "-Djdk.internal.lambda.dumpProxyClasses=dumpLong",
 234                                "-Djava.security.manager",
 235                                longFQCN);
 236         assertEquals(tr.testOutput.stream()
 237                                   .filter(s -> s.startsWith("WARNING: Exception"))
 238                                   .count(),
 239                      2, "show error each capture");
 240         // dumpLong/com/example/nonsense/nonsense
 241         Path dumpPath = Paths.get("dumpLong/com/example/nonsense");
 242         Predicate<Path> filter = p -> p.getParent() == null || dumpPath.startsWith(p) || p.startsWith(dumpPath);
 243         boolean debug = true;
 244         if (debug) {
 245            Files.walk(Paths.get("dumpLong"))
 246                 .forEachOrdered(p -> {
 247                     if (filter.test(p)) {
 248                         System.out.println("accepted: " + p.toString());
 249                     } else {
 250                         System.out.println("filetered out: " + p.toString());
 251                     }
 252                  });
 253         }
 254         assertEquals(Files.walk(Paths.get("dumpLong"))
 255                 .filter(filter)
 256                 .count(), 5, "Two lambda captured failed to log");
 257         tr.assertZero("Should still return 0");
 258     }
 259 }