1 /*
   2  * Copyright (c) 2017, 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.event.runtime;
  26 
  27 import java.util.HashMap;
  28 import java.util.List;
  29 import java.util.Map;
  30 
  31 import jdk.jfr.Configuration;
  32 import jdk.jfr.Event;
  33 import jdk.jfr.EventType;
  34 import jdk.jfr.FlightRecorder;
  35 import jdk.jfr.Recording;
  36 import jdk.jfr.Registered;
  37 import jdk.jfr.SettingDescriptor;
  38 import jdk.jfr.consumer.RecordedEvent;
  39 import jdk.test.lib.Asserts;
  40 import jdk.test.lib.jfr.EventNames;
  41 import jdk.test.lib.jfr.Events;
  42 
  43 /**
  44  * @test
  45  * @summary Tests that active setting are available in the ActiveSettingevent
  46  * @key jfr
  47  * @requires vm.hasJFR
  48  * @library /test/lib
  49  * @run main/othervm jdk.jfr.event.runtime.TestActiveSettingEvent
  50  */
  51 public final class TestActiveSettingEvent {
  52 
  53     private static class MyEvent extends Event {
  54     }
  55 
  56     @Registered(false)
  57     private static class MyRegistrationEvent extends Event {
  58     }
  59 
  60     private static final String ACTIVE_SETTING_EVENT_NAME = EventNames.ActiveSetting;
  61 
  62     public static void main(String[] args) throws Throwable {
  63         testDefaultSettings();;
  64         testProfileSettings();;
  65         testNewSettings();
  66         testChangedSetting();
  67         testUnregistered();
  68         testRegistration();
  69     }
  70 
  71     private static void testProfileSettings() throws Exception {
  72         testSettingConfiguration("profile");
  73     }
  74 
  75     private static void testDefaultSettings() throws Exception {
  76         testSettingConfiguration("default");
  77     }
  78 
  79     private static void testRegistration() throws Exception {
  80         // Register new
  81         try (Recording recording = new Recording()) {
  82             recording.enable(ACTIVE_SETTING_EVENT_NAME);
  83             recording.start();
  84             FlightRecorder.register(MyRegistrationEvent.class);
  85             recording.stop();
  86             List<RecordedEvent> events = Events.fromRecording(recording);
  87             Events.hasEvents(events);
  88             EventType type = EventType.getEventType(MyRegistrationEvent.class);
  89             assertSetting(events, type, "threshold", "0 ns");
  90             assertSetting(events, type, "enabled", "true");
  91             assertSetting(events, type, "stackTrace", "true");
  92         }
  93         // Register unregistered
  94         FlightRecorder.unregister(MyEvent.class);
  95         try (Recording recording = new Recording()) {
  96             recording.enable(ACTIVE_SETTING_EVENT_NAME);
  97             recording.start();
  98             FlightRecorder.register(MyRegistrationEvent.class);
  99             recording.stop();
 100             EventType type = EventType.getEventType(MyRegistrationEvent.class);
 101             List<RecordedEvent> events = Events.fromRecording(recording);
 102             Events.hasEvents(events);
 103             type = EventType.getEventType(MyRegistrationEvent.class);
 104             assertSetting(events, type, "threshold", "0 ns");
 105             assertSetting(events, type, "enabled", "true");
 106             assertSetting(events, type, "stackTrace", "true");
 107         }
 108     }
 109 
 110     private static void testUnregistered() throws Exception {
 111         FlightRecorder.register(MyEvent.class);
 112         EventType type = EventType.getEventType(MyEvent.class);
 113         FlightRecorder.unregister(MyEvent.class);
 114         try (Recording recording = new Recording()) {
 115             recording.enable(ACTIVE_SETTING_EVENT_NAME);
 116             recording.start();
 117             MyEvent m = new MyEvent();
 118             m.commit();
 119             recording.stop();
 120             List<RecordedEvent> events = Events.fromRecording(recording);
 121             Events.hasEvents(events);
 122             assertNotSetting(events, type, "threshold", "0 ns");
 123             assertNotSetting(events, type, "enabled", "true");
 124             assertNotSetting(events, type, "stackTrace", "true");
 125         }
 126     }
 127 
 128     private static void testNewSettings() throws Exception {
 129         try (Recording recording = new Recording()) {
 130             recording.enable(ACTIVE_SETTING_EVENT_NAME);
 131             recording.start();
 132             MyEvent m = new MyEvent();
 133             m.commit();
 134             recording.stop();
 135             List<RecordedEvent> events = Events.fromRecording(recording);
 136             Events.hasEvents(events);
 137             EventType type = EventType.getEventType(MyEvent.class);
 138             assertSetting(events, type, "threshold", "0 ns");
 139             assertSetting(events, type, "enabled", "true");
 140             assertSetting(events, type, "stackTrace", "true");
 141             assertNotSetting(events, type, "period", "everyChunk");
 142         }
 143     }
 144 
 145     private static void testChangedSetting() throws Exception {
 146         EventType type = EventType.getEventType(MyEvent.class);
 147         Map<String, String> base = new HashMap<>();
 148         base.put(ACTIVE_SETTING_EVENT_NAME + "#enabled", "true");
 149         try (Recording recording = new Recording()) {
 150             recording.setSettings(base);
 151             recording.start();
 152             Map<String, String> newS = new HashMap<>(base);
 153             newS.put(type.getName() + "#enabled", "true");
 154             newS.put(type.getName() + "#threshold", "11 ns");
 155             recording.setSettings(newS);
 156             recording.stop();
 157             List<RecordedEvent> events = Events.fromRecording(recording);
 158             Events.hasEvents(events);
 159             assertSetting(events, type, "threshold", "0 ns"); // initial value
 160             assertSetting(events, type, "enabled", "true");
 161             assertSetting(events, type, "threshold", "11 ns"); // changed value
 162         }
 163     }
 164 
 165     private static void assertSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
 166         if (!hasSetting(events, evenType, settingName, settingValue)) {
 167             throw new Exception("Could not find setting " + settingName + " with value " + settingValue + " for event type " + evenType.getName());
 168         }
 169     }
 170 
 171     private static void assertNotSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
 172         if (hasSetting(events, evenType, settingName, settingValue)) {
 173             throw new Exception("Found unexpected setting " + settingName + " with value " + settingValue + " for event type " + evenType.getName());
 174         }
 175     }
 176 
 177     private static boolean hasSetting(List<RecordedEvent> events, EventType evenType, String settingName, String settingValue) throws Exception {
 178         for (RecordedEvent e : events) {
 179             if (e.getEventType().getName().equals(ACTIVE_SETTING_EVENT_NAME)) {
 180                 String name = e.getValue("name");
 181                 String value = e.getValue("value");
 182                 Long id = e.getValue("id");
 183                 if (evenType.getId() == id && name.equals(settingName) && settingValue.equals(value)) {
 184                     return true;
 185                 }
 186             }
 187         }
 188         return false;
 189     }
 190 
 191     private static void testSettingConfiguration(String configurationName) throws Exception {
 192         System.out.println("Testing configuration " + configurationName);
 193         Configuration c = Configuration.getConfiguration(configurationName);
 194         Map<String, String> settingValues = c.getSettings();
 195         // Don't want to add these settings to the jfc-files we ship since they
 196         // are not useful to configure. They are however needed to make the test
 197         // pass.
 198         settingValues.put(EventNames.ActiveSetting + "#stackTrace", "false");
 199         settingValues.put(EventNames.ActiveSetting + "#threshold", "0 ns");
 200         settingValues.put(EventNames.ActiveRecording + "#stackTrace", "false");
 201         settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns");
 202         settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns");
 203         settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns");
 204         settingValues.put(EventNames.SecurityProperty + "#threshold", "0 ns");
 205         settingValues.put(EventNames.TLSHandshake + "#threshold", "0 ns");
 206         settingValues.put(EventNames.X509Certificate + "#threshold", "0 ns");
 207         settingValues.put(EventNames.X509Validation + "#threshold", "0 ns");
 208 
 209         try (Recording recording = new Recording(c)) {
 210             Map<Long, EventType> eventTypes = new HashMap<>();
 211             for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) {
 212                 eventTypes.put(et.getId(), et);
 213             }
 214             recording.start();
 215             Map<String, String> expectedSettings = new HashMap<>();
 216             for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) {
 217                 for (SettingDescriptor s : type.getSettingDescriptors()) {
 218                     String settingName = type.getName() + "#" + s.getName();
 219                     String value = settingValues.get(settingName);
 220                     if (value == null) {
 221                         throw new Exception("Could not find setting with name " + settingName);
 222                     }
 223                     // Prefer to have ms unit in jfc file
 224                     if (value.equals("0 ms")) {
 225                         value = "0 ns";
 226                     }
 227                     expectedSettings.put(settingName, value);
 228                 }
 229             }
 230             recording.stop();
 231 
 232             for (RecordedEvent e : Events.fromRecording(recording)) {
 233                 if (e.getEventType().getName().equals(ACTIVE_SETTING_EVENT_NAME)) {
 234                     Long id = e.getValue("id");
 235                     EventType et = eventTypes.get(id);
 236                     if (et == null) {
 237                         throw new Exception("Could not find event type with id " + id);
 238                     }
 239                     String name = e.getValue("name");
 240                     String settingName = et.getName() + "#" + name;
 241                     String value = e.getValue("value");
 242                     String expectedValue = expectedSettings.get(settingName);
 243                     if (expectedValue != null) {
 244                         if (value.equals("0 ms")) {
 245                             value = "0 ns";
 246                         }
 247                         Asserts.assertEquals(expectedValue, value, "Incorrect settings value for " + settingName + " was " + value + ", expected " + expectedValue);
 248                         expectedSettings.remove(settingName);
 249                     }
 250                 }
 251             }
 252             if (!expectedSettings.isEmpty()) {
 253                 throw new Exception("Not all setting in event. Missing " + expectedSettings.keySet());
 254             }
 255         }
 256     }
 257 }