test/jdk/jdk/jfr/api/event/dynamic/TestEventFactory.java
changeset 50113 caf115bb98ad
child 51214 67736b4846a0
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 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 
       
    26 package jdk.jfr.api.event.dynamic;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.lang.annotation.ElementType;
       
    30 import java.lang.annotation.Retention;
       
    31 import java.lang.annotation.RetentionPolicy;
       
    32 import java.lang.annotation.Target;
       
    33 import java.util.ArrayList;
       
    34 import java.util.Collections;
       
    35 import java.util.Comparator;
       
    36 import java.util.HashMap;
       
    37 import java.util.List;
       
    38 import java.util.Map;
       
    39 
       
    40 import jdk.jfr.AnnotationElement;
       
    41 import jdk.jfr.Event;
       
    42 import jdk.jfr.EventFactory;
       
    43 import jdk.jfr.EventType;
       
    44 import jdk.jfr.MetadataDefinition;
       
    45 import jdk.jfr.Recording;
       
    46 import jdk.jfr.ValueDescriptor;
       
    47 import jdk.jfr.consumer.RecordedClass;
       
    48 import jdk.jfr.consumer.RecordedEvent;
       
    49 import jdk.jfr.consumer.RecordedThread;
       
    50 import jdk.jfr.consumer.RecordingFile;
       
    51 import jdk.test.lib.Asserts;
       
    52 import jdk.test.lib.jfr.EventTypePrototype;
       
    53 import jdk.test.lib.jfr.Events;
       
    54 
       
    55 
       
    56 /*
       
    57  * @test
       
    58  * @key jfr
       
    59  * @library /test/lib
       
    60  * @run main/othervm jdk.jfr.api.event.dynamic.TestEventFactory
       
    61  */
       
    62 public class TestEventFactory {
       
    63 
       
    64     @MetadataDefinition
       
    65     @Retention(RetentionPolicy.RUNTIME)
       
    66     @Target({ ElementType.FIELD, ElementType.TYPE })
       
    67     public @interface TestAnnotation {
       
    68         String value();
       
    69     }
       
    70 
       
    71     public final static Map<String, Object> EVENT_VALUES = new HashMap<>();
       
    72     public final static EventTypePrototype EVENT_TYPE_SHOULD_NOT_COMMIT;
       
    73     public final static EventTypePrototype EVENT_TYPE_SHOULD_COMMIT;
       
    74 
       
    75     // keep alive to prevent event metadata getting GC.
       
    76     public static EventFactory ef1;
       
    77     public static EventFactory ef2;
       
    78 
       
    79     static {
       
    80         EVENT_VALUES.put("intField", Integer.MAX_VALUE);
       
    81         EVENT_VALUES.put("longField", Long.MAX_VALUE);
       
    82         EVENT_VALUES.put("byteField", (byte) 5);
       
    83         EVENT_VALUES.put("charField", (char) 'H');
       
    84         EVENT_VALUES.put("shortField", (short) 56);
       
    85         EVENT_VALUES.put("booleanField", true);
       
    86         EVENT_VALUES.put("floatField", 4711.0f);
       
    87         EVENT_VALUES.put("doubleField", 3.141);
       
    88         EVENT_VALUES.put("classField", String.class);
       
    89         EVENT_VALUES.put("stringField", "Yeah!");
       
    90         EVENT_VALUES.put("threadField", Thread.currentThread());
       
    91 
       
    92         EVENT_TYPE_SHOULD_NOT_COMMIT = makeEventType("com.test.ShouldNotCommit");
       
    93         EVENT_TYPE_SHOULD_COMMIT = makeEventType("com.test.ShouldCommit");
       
    94     }
       
    95 
       
    96     public static void main(String[] args) throws Throwable {
       
    97         Recording r = new Recording();
       
    98         r.enable(EVENT_TYPE_SHOULD_COMMIT.getName()).withoutStackTrace();
       
    99         r.enable(EVENT_TYPE_SHOULD_NOT_COMMIT.getName()).withoutStackTrace();
       
   100 
       
   101         // Commit before start, should not be included
       
   102         ef1 = EventFactory.create(EVENT_TYPE_SHOULD_NOT_COMMIT.getAnnotations(), EVENT_TYPE_SHOULD_NOT_COMMIT.getFields());
       
   103 
       
   104         Event event1 = ef1.newEvent();
       
   105 
       
   106         setEventValues(event1, ef1, EVENT_TYPE_SHOULD_NOT_COMMIT);
       
   107         event1.commit();
       
   108 
       
   109         r.start();
       
   110         // Commit after start, should be included
       
   111         ef2 = EventFactory.create(EVENT_TYPE_SHOULD_COMMIT.getAnnotations(),  EVENT_TYPE_SHOULD_COMMIT.getFields());
       
   112 
       
   113         Event event2 = ef2.newEvent();
       
   114         setEventValues(event2, ef2, EVENT_TYPE_SHOULD_COMMIT);
       
   115         event2.commit();
       
   116 
       
   117         r.stop();
       
   118 
       
   119         RecordingFile es = Events.copyTo(r);
       
   120         EventType e1 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_NOT_COMMIT.getName());
       
   121         assertEquals(e1, ef1.getEventType());
       
   122 
       
   123         EventType e2 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_COMMIT.getName());
       
   124         assertEquals(e2, ef2.getEventType());
       
   125 
       
   126         verifyEvent(es);
       
   127     }
       
   128 
       
   129     private static EventType findEventType(List<EventType> es, String name) {
       
   130         for (EventType t : es) {
       
   131             if (t.getName().equals(name)) {
       
   132                 return t;
       
   133             }
       
   134         }
       
   135         throw new AssertionError("Could not find expected event type " + name);
       
   136     }
       
   137 
       
   138     private static void assertEquals(EventType e1, EventType expected) {
       
   139         Asserts.assertEquals(e1.getName(), expected.getName());
       
   140         Asserts.assertEquals(e1.getDescription(), expected.getDescription());
       
   141         Asserts.assertEquals(e1.getLabel(), expected.getLabel());
       
   142         assertValueDescriptorEquals(e1.getFields(), expected.getFields());
       
   143         assertAnnotationEquals(e1.getAnnotationElements(), expected.getAnnotationElements());
       
   144     }
       
   145 
       
   146     private static void assertValueDescriptorEquals(List<ValueDescriptor> values, List<ValueDescriptor> expected) {
       
   147         if (values.isEmpty() && expected.isEmpty()) {
       
   148             return;
       
   149         }
       
   150 
       
   151         Map<String, ValueDescriptor> valueMap = new HashMap<>();
       
   152         for (ValueDescriptor v : values) {
       
   153             valueMap.put(v.getName(), v);
       
   154         }
       
   155         for (ValueDescriptor f : expected) {
       
   156             ValueDescriptor v = valueMap.remove(f.getName());
       
   157             if (v == null) {
       
   158                 throw new AssertionError("Expected value descriptor " + f.getName() + " not found");
       
   159             }
       
   160             assertEquals(v, f);
       
   161         }
       
   162         if (!valueMap.isEmpty()) {
       
   163             throw new AssertionError("More fields than expected");
       
   164         }
       
   165     }
       
   166 
       
   167     private static void assertEquals(ValueDescriptor v1, ValueDescriptor expected) {
       
   168         Asserts.assertEquals(v1.getName(), expected.getName());
       
   169         Asserts.assertEquals(v1.getTypeName(), expected.getTypeName());
       
   170         assertAnnotationEquals(v1.getAnnotationElements(), expected.getAnnotationElements());
       
   171     }
       
   172 
       
   173     private static void assertAnnotationEquals(List<AnnotationElement> annotations, List<AnnotationElement> expected) {
       
   174         annotations = new ArrayList<>(annotations); // make mutable
       
   175         expected = new ArrayList<>(expected); // make mutable
       
   176         class AnnotationTypeComparator implements Comparator<AnnotationElement> {
       
   177             @Override
       
   178             public int compare(AnnotationElement a, AnnotationElement b) {
       
   179                 return a.getTypeName().compareTo(b.getTypeName());
       
   180             }
       
   181         }
       
   182 
       
   183         if (annotations.isEmpty() && expected.isEmpty()) {
       
   184             return;
       
   185         }
       
   186 
       
   187         if (annotations.size() != expected.size()) {
       
   188             System.out.println("Was:");
       
   189             for(AnnotationElement ae: annotations) {
       
   190                 System.out.println(ae.getTypeName());
       
   191             }
       
   192             System.out.println("Expected:");
       
   193             for(AnnotationElement ae: expected) {
       
   194                 System.out.println(ae.getTypeName());
       
   195             }
       
   196             throw new AssertionError("Wrong number of annotations");
       
   197         }
       
   198         Collections.sort(expected, new AnnotationTypeComparator());
       
   199         Collections.sort(annotations, new AnnotationTypeComparator());
       
   200         for (int i = 0; i < expected.size(); i++) {
       
   201             assertEquals(annotations.get(i), expected.get(i));
       
   202         }
       
   203     }
       
   204 
       
   205     private static void assertEquals(AnnotationElement a1, AnnotationElement expected) {
       
   206         Asserts.assertEquals(a1.getTypeName(), expected.getTypeName());
       
   207         // Don't recurse into annotation
       
   208         assertValueDescriptorEquals(a1.getValueDescriptors(), expected.getValueDescriptors());
       
   209     }
       
   210 
       
   211     private static void verifyEvent(RecordingFile rf) throws IOException {
       
   212         if (!rf.hasMoreEvents()) {
       
   213             throw new AssertionError("Expected one dynamic event");
       
   214         }
       
   215         verifyValues(rf.readEvent());
       
   216         if (rf.hasMoreEvents()) {
       
   217             throw new AssertionError("Expected one dynamic event");
       
   218         }
       
   219     }
       
   220 
       
   221     private static void setEventValues(Event event, EventFactory f, EventTypePrototype eventTypeProto) {
       
   222         for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
       
   223             int index = eventTypeProto.getFieldIndex(entry.getKey());
       
   224             event.set(index, entry.getValue());
       
   225         }
       
   226     }
       
   227 
       
   228     private static void verifyValues(RecordedEvent event) {
       
   229         for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
       
   230             String fieldName = entry.getKey();
       
   231             Object value = event.getValue(fieldName);
       
   232             Object expected = EVENT_VALUES.get(fieldName);
       
   233             if (expected instanceof Class) {
       
   234                 value = ((RecordedClass) value).getName();
       
   235                 expected = ((Class<?>) expected).getName();
       
   236             }
       
   237             if (expected instanceof Thread) {
       
   238                 value = ((RecordedThread) value).getJavaName();
       
   239                 expected = ((Thread) expected).getName();
       
   240             }
       
   241             Asserts.assertEQ(value, expected);
       
   242         }
       
   243     }
       
   244 
       
   245     private static EventTypePrototype makeEventType(String eventName) {
       
   246         EventTypePrototype prototype = new EventTypePrototype(eventName);
       
   247         prototype.addAnnotation(new AnnotationElement(TestAnnotation.class, "type"));
       
   248         for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
       
   249             Class<?> type = makePrimitive(entry.getValue().getClass());
       
   250             String fieldName = entry.getKey();
       
   251             prototype.addField(new ValueDescriptor(type, fieldName));
       
   252         }
       
   253         // add an annotated field
       
   254         List<AnnotationElement> annos = new ArrayList<>();
       
   255         annos.add(new AnnotationElement(TestAnnotation.class, "field"));
       
   256         prototype.addField( new ValueDescriptor(int.class, "annotatedField", annos));
       
   257 
       
   258         return prototype;
       
   259     }
       
   260 
       
   261     private static Class<?> makePrimitive(Class<? extends Object> clazz) {
       
   262         if (clazz == Integer.class) {
       
   263             return int.class;
       
   264         }
       
   265         if (clazz == Long.class) {
       
   266             return long.class;
       
   267         }
       
   268         if (clazz == Double.class) {
       
   269             return double.class;
       
   270         }
       
   271         if (clazz == Float.class) {
       
   272             return float.class;
       
   273         }
       
   274         if (clazz == Short.class) {
       
   275             return short.class;
       
   276         }
       
   277         if (clazz == Character.class) {
       
   278             return char.class;
       
   279         }
       
   280         if (clazz == Byte.class) {
       
   281             return byte.class;
       
   282         }
       
   283         if (clazz == Boolean.class) {
       
   284             return boolean.class;
       
   285         }
       
   286         return clazz;
       
   287     }
       
   288 }