1 /*
   2  * Copyright (c) 2014, 2018, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.jfr.jvm;
  26 
  27 
  28 import java.io.FileReader;
  29 import java.io.IOException;
  30 import java.nio.file.Files;
  31 import java.nio.file.Path;
  32 import java.nio.file.Paths;
  33 import java.util.ArrayList;
  34 import java.util.concurrent.Callable;
  35 
  36 import jdk.jfr.AnnotationElement;
  37 import jdk.jfr.Configuration;
  38 import jdk.jfr.Description;
  39 import jdk.jfr.Event;
  40 import jdk.jfr.EventFactory;
  41 import jdk.jfr.EventSettings;
  42 import jdk.jfr.EventType;
  43 import jdk.jfr.FlightRecorder;
  44 import jdk.jfr.FlightRecorderListener;
  45 import jdk.jfr.FlightRecorderPermission;
  46 import jdk.jfr.Label;
  47 import jdk.jfr.Recording;
  48 import jdk.jfr.RecordingState;
  49 import jdk.jfr.SettingControl;
  50 import jdk.jfr.ValueDescriptor;
  51 import jdk.jfr.consumer.RecordedClass;
  52 import jdk.jfr.consumer.RecordedEvent;
  53 import jdk.jfr.consumer.RecordedFrame;
  54 import jdk.jfr.consumer.RecordedMethod;
  55 import jdk.jfr.consumer.RecordedObject;
  56 import jdk.jfr.consumer.RecordedStackTrace;
  57 import jdk.jfr.consumer.RecordedThread;
  58 import jdk.jfr.consumer.RecordedThreadGroup;
  59 import jdk.jfr.consumer.RecordingFile;
  60 import jdk.management.jfr.ConfigurationInfo;
  61 import jdk.management.jfr.EventTypeInfo;
  62 import jdk.management.jfr.FlightRecorderMXBean;
  63 import jdk.management.jfr.RecordingInfo;
  64 import jdk.management.jfr.SettingDescriptorInfo;
  65 import jdk.test.lib.Utils;
  66 
  67 /**
  68  * @test TestUnsupportedVM
  69  * @key jfr
  70  * 
  71  *
  72  * 
  73  *
  74  * @library /lib /
  75  * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
  76  * @run main/othervm -Djfr.unsupported.vm=true jdk.jfr.jvm.TestUnsupportedVM
  77  */
  78 public class TestUnsupportedVM {
  79 
  80     private static Path RECORDING_FILE = Paths.get("recording.jfr");
  81     private static Class<?> [] APIClasses = {
  82             AnnotationElement.class,
  83             Configuration.class,
  84             ConfigurationInfo.class,
  85             Event.class,
  86             EventFactory.class,
  87             EventSettings.class,
  88             EventType.class,
  89             EventTypeInfo.class,
  90             FlightRecorder.class,
  91             FlightRecorderPermission.class,
  92             FlightRecorderListener.class,
  93             FlightRecorderMXBean.class,
  94             RecordedClass.class,
  95             RecordedEvent.class,
  96             RecordedFrame.class,
  97             RecordedMethod.class,
  98             RecordedObject.class,
  99             RecordedStackTrace.class,
 100             RecordedThread.class,
 101             RecordedThreadGroup.class,
 102             Recording.class,
 103             RecordingFile.class,
 104             RecordingInfo.class,
 105             RecordingState.class,
 106             SettingControl.class,
 107             SettingDescriptorInfo.class,
 108             ValueDescriptor.class
 109        };
 110     // * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
 111     @Label("My Event")
 112     @Description("My fine event")
 113     static class MyEvent extends Event {
 114         int myValue;
 115     }
 116 
 117     public static void main(String... args) throws Exception {
 118         if (Boolean.getBoolean("prepare-recording")) {
 119             Recording r = new Recording(Configuration.getConfiguration("default"));
 120             r.start();
 121             r.stop();
 122             r.dump(RECORDING_FILE);
 123             r.close();
 124             return;
 125         }
 126 
 127         System.out.println("jdk.jfr.unsupportedvm=" + System.getProperty("jdk.jfr.unsupportedvm"));
 128         // Class FlightRecorder
 129         if (FlightRecorder.isAvailable()) {
 130             throw new AssertionError("JFR should not be available on an unsupported VM");
 131         }
 132 
 133         if (FlightRecorder.isInitialized()) {
 134             throw new AssertionError("JFR should not be initialized on an unsupported VM");
 135         }
 136 
 137         assertIllegalStateException(() -> FlightRecorder.getFlightRecorder());
 138         assertSwallow(() -> FlightRecorder.addListener(new FlightRecorderListener() {}));
 139         assertSwallow(() -> FlightRecorder.removeListener(new FlightRecorderListener() {}));
 140         assertSwallow(() -> FlightRecorder.register(MyEvent.class));
 141         assertSwallow(() -> FlightRecorder.unregister(MyEvent.class));
 142         assertSwallow(() -> FlightRecorder.addPeriodicEvent(MyEvent.class, new Runnable() { public void run() {} }));
 143         assertSwallow(() -> FlightRecorder.removePeriodicEvent(new Runnable() { public void run() {} }));
 144 
 145         // Class Configuration
 146         if (!Configuration.getConfigurations().isEmpty()) {
 147             throw new AssertionError("Configuration files should not exist on an unsupported VM");
 148         }
 149         Path jfcFile = Utils.createTempFile("empty", ".jfr");
 150         assertIOException(() -> Configuration.getConfiguration("default"));
 151         assertIOException(() -> Configuration.create(jfcFile));
 152         assertIOException(() -> Configuration.create(new FileReader(jfcFile.toFile())));
 153 
 154         // Class EventType
 155         assertInternalError(() -> EventType.getEventType(MyEvent.class));
 156 
 157         // Class EventFactory
 158         assertInternalError(() -> EventFactory.create(new ArrayList<>(), new ArrayList<>()));
 159 
 160         // Create a static event
 161         MyEvent myEvent = new MyEvent();
 162         myEvent.begin();
 163         myEvent.end();
 164         myEvent.shouldCommit();
 165         myEvent.commit();
 166 
 167         // Trigger class initialization failure
 168         for (Class<?> c : APIClasses) {
 169             assertNoClassInitFailure(c);
 170         }
 171 
 172         // jdk.jfr.consumer.*
 173         // Only run this part of tests if we are on VM
 174         // that can produce a recording file
 175         if (Files.exists(RECORDING_FILE)) {
 176             for(RecordedEvent re : RecordingFile.readAllEvents(RECORDING_FILE)) {
 177                 System.out.println(re);
 178             }
 179         }
 180     }
 181 
 182     private static void assertNoClassInitFailure(Class<?> clazz) {
 183         try {
 184             Class.forName(clazz.getName(), true, clazz.getClassLoader());
 185         } catch (ClassNotFoundException e) {
 186             throw new AssertionError("Could not find public API class on unsupported VM");
 187         }
 188     }
 189 
 190     private static void assertInternalError(Runnable r) {
 191         try {
 192             r.run();
 193         } catch (InternalError e) {
 194            // OK, as expected
 195             return;
 196         }
 197         throw new AssertionError("Expected InternalError on an unsupported JVM");
 198     }
 199 
 200     private static void assertIOException(Callable<?> c) {
 201         try {
 202             c.call();
 203         } catch (Exception e) {
 204             if (e.getClass() == IOException.class) {
 205                 return;
 206             }
 207         }
 208         throw new AssertionError("Expected IOException on an unsupported JVM");
 209     }
 210 
 211     private static void assertIllegalStateException(Runnable r) throws Exception {
 212         try {
 213             r.run();
 214         } catch (IllegalStateException ise) {
 215             if (!ise.getMessage().equals("Flight Recorder is not supported on this VM")) {
 216                 throw new AssertionError("Expected 'Flight Recorder is not supported on this VM'");
 217             }
 218         }
 219     }
 220 
 221     private static void assertSwallow(Runnable r) throws Exception {
 222         try {
 223             r.run();
 224         } catch (Exception e) {
 225             throw new AssertionError("Unexpected exception '" + e.getMessage() + " on an unspported VM");
 226         }
 227     }
 228 }