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 
  66 /*
  67  * @test TestUnsupportedVM
  68  * @key jfr
  69  *
  70  * @modules jdk.jfr
  71  *          jdk.management.jfr
  72  *
  73  * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
  74  * @run main/othervm -Djfr.unsupported.vm=true jdk.jfr.jvm.TestUnsupportedVM
  75  */
  76 public class TestUnsupportedVM {
  77 
  78     private static Path RECORDING_FILE = Paths.get("recording.jfr");
  79     private static Class<?> [] APIClasses = {
  80             AnnotationElement.class,
  81             Configuration.class,
  82             ConfigurationInfo.class,
  83             Event.class,
  84             EventFactory.class,
  85             EventSettings.class,
  86             EventType.class,
  87             EventTypeInfo.class,
  88             FlightRecorder.class,
  89             FlightRecorderPermission.class,
  90             FlightRecorderListener.class,
  91             FlightRecorderMXBean.class,
  92             RecordedClass.class,
  93             RecordedEvent.class,
  94             RecordedFrame.class,
  95             RecordedMethod.class,
  96             RecordedObject.class,
  97             RecordedStackTrace.class,
  98             RecordedThread.class,
  99             RecordedThreadGroup.class,
 100             Recording.class,
 101             RecordingFile.class,
 102             RecordingInfo.class,
 103             RecordingState.class,
 104             SettingControl.class,
 105             SettingDescriptorInfo.class,
 106             ValueDescriptor.class
 107        };
 108     // * @run main/othervm -Dprepare-recording=true jdk.jfr.jvm.TestUnsupportedVM
 109     @Label("My Event")
 110     @Description("My fine event")
 111     static class MyEvent extends Event {
 112         int myValue;
 113     }
 114 
 115     public static void main(String... args) throws Exception {
 116         if (Boolean.getBoolean("prepare-recording")) {
 117             Recording r = new Recording(Configuration.getConfiguration("default"));
 118             r.start();
 119             r.stop();
 120             r.dump(RECORDING_FILE);
 121             r.close();
 122             return;
 123         }
 124 
 125         System.out.println("jdk.jfr.unsupportedvm=" + System.getProperty("jdk.jfr.unsupportedvm"));
 126         // Class FlightRecorder
 127         if (FlightRecorder.isAvailable()) {
 128             throw new AssertionError("JFR should not be available on an unsupported VM");
 129         }
 130 
 131         if (FlightRecorder.isInitialized()) {
 132             throw new AssertionError("JFR should not be initialized on an unsupported VM");
 133         }
 134 
 135         assertIllegalStateException(() -> FlightRecorder.getFlightRecorder());
 136         assertSwallow(() -> FlightRecorder.addListener(new FlightRecorderListener() {}));
 137         assertSwallow(() -> FlightRecorder.removeListener(new FlightRecorderListener() {}));
 138         assertSwallow(() -> FlightRecorder.register(MyEvent.class));
 139         assertSwallow(() -> FlightRecorder.unregister(MyEvent.class));
 140         assertSwallow(() -> FlightRecorder.addPeriodicEvent(MyEvent.class, new Runnable() { public void run() {} }));
 141         assertSwallow(() -> FlightRecorder.removePeriodicEvent(new Runnable() { public void run() {} }));
 142 
 143         // Class Configuration
 144         if (!Configuration.getConfigurations().isEmpty()) {
 145             throw new AssertionError("Configuration files should not exist on an unsupported VM");
 146         }
 147         Path jfcFile = Files.createTempFile("my", ".jfr");
 148         assertIOException(() -> Configuration.getConfiguration("default"));
 149         assertIOException(() -> Configuration.create(jfcFile));
 150         assertIOException(() -> Configuration.create(new FileReader(jfcFile.toFile())));
 151 
 152         // Class EventType
 153         assertInternalError(() -> EventType.getEventType(MyEvent.class));
 154 
 155         // Class EventFactory
 156         assertInternalError(() -> EventFactory.create(new ArrayList<>(), new ArrayList<>()));
 157 
 158         // Create a static event
 159         MyEvent myEvent = new MyEvent();
 160         myEvent.begin();
 161         myEvent.end();
 162         myEvent.shouldCommit();
 163         myEvent.commit();
 164 
 165         // Trigger class initialization failure
 166         for (Class<?> c : APIClasses) {
 167             assertNoClassInitFailure(c);
 168         }
 169 
 170         // jdk.jfr.consumer.*
 171         // Only run this part of tests if we are on VM
 172         // that can produce a recording file
 173         if (Files.exists(RECORDING_FILE)) {
 174             for(RecordedEvent re : RecordingFile.readAllEvents(RECORDING_FILE)) {
 175                 System.out.println(re);
 176             }
 177         }
 178     }
 179 
 180     private static void assertNoClassInitFailure(Class<?> clazz) {
 181         try {
 182             Class.forName(clazz.getName(), true, clazz.getClassLoader());
 183         } catch (ClassNotFoundException e) {
 184             throw new AssertionError("Could not find public API class on unsupported VM");
 185         }
 186     }
 187 
 188     private static void assertInternalError(Runnable r) {
 189         try {
 190             r.run();
 191         } catch (InternalError e) {
 192            // OK, as expected
 193             return;
 194         }
 195         throw new AssertionError("Expected InternalError on an unsupported JVM");
 196     }
 197 
 198     private static void assertIOException(Callable<?> c) {
 199         try {
 200             c.call();
 201         } catch (Exception e) {
 202             if (e.getClass() == IOException.class) {
 203                 return;
 204             }
 205         }
 206         throw new AssertionError("Expected IOException on an unsupported JVM");
 207     }
 208 
 209     private static void assertIllegalStateException(Runnable r) throws Exception {
 210         try {
 211             r.run();
 212         } catch (IllegalStateException ise) {
 213             if (!ise.getMessage().equals("Flight Recorder is not supported on this VM")) {
 214                 throw new AssertionError("Expected 'Flight Recorder is not supported on this VM'");
 215             }
 216         }
 217     }
 218 
 219     private static void assertSwallow(Runnable r) throws Exception {
 220         try {
 221             r.run();
 222         } catch (Exception e) {
 223             throw new AssertionError("Unexpected exception '" + e.getMessage() + " on an unspported VM");
 224         }
 225     }
 226 }