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