test/jdk/jdk/jfr/api/event/dynamic/TestEventFactory.java
changeset 50113 caf115bb98ad
child 51214 67736b4846a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/api/event/dynamic/TestEventFactory.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.api.event.dynamic;
+
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.Event;
+import jdk.jfr.EventFactory;
+import jdk.jfr.EventType;
+import jdk.jfr.MetadataDefinition;
+import jdk.jfr.Recording;
+import jdk.jfr.ValueDescriptor;
+import jdk.jfr.consumer.RecordedClass;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedThread;
+import jdk.jfr.consumer.RecordingFile;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventTypePrototype;
+import jdk.test.lib.jfr.Events;
+
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.api.event.dynamic.TestEventFactory
+ */
+public class TestEventFactory {
+
+    @MetadataDefinition
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ ElementType.FIELD, ElementType.TYPE })
+    public @interface TestAnnotation {
+        String value();
+    }
+
+    public final static Map<String, Object> EVENT_VALUES = new HashMap<>();
+    public final static EventTypePrototype EVENT_TYPE_SHOULD_NOT_COMMIT;
+    public final static EventTypePrototype EVENT_TYPE_SHOULD_COMMIT;
+
+    // keep alive to prevent event metadata getting GC.
+    public static EventFactory ef1;
+    public static EventFactory ef2;
+
+    static {
+        EVENT_VALUES.put("intField", Integer.MAX_VALUE);
+        EVENT_VALUES.put("longField", Long.MAX_VALUE);
+        EVENT_VALUES.put("byteField", (byte) 5);
+        EVENT_VALUES.put("charField", (char) 'H');
+        EVENT_VALUES.put("shortField", (short) 56);
+        EVENT_VALUES.put("booleanField", true);
+        EVENT_VALUES.put("floatField", 4711.0f);
+        EVENT_VALUES.put("doubleField", 3.141);
+        EVENT_VALUES.put("classField", String.class);
+        EVENT_VALUES.put("stringField", "Yeah!");
+        EVENT_VALUES.put("threadField", Thread.currentThread());
+
+        EVENT_TYPE_SHOULD_NOT_COMMIT = makeEventType("com.test.ShouldNotCommit");
+        EVENT_TYPE_SHOULD_COMMIT = makeEventType("com.test.ShouldCommit");
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Recording r = new Recording();
+        r.enable(EVENT_TYPE_SHOULD_COMMIT.getName()).withoutStackTrace();
+        r.enable(EVENT_TYPE_SHOULD_NOT_COMMIT.getName()).withoutStackTrace();
+
+        // Commit before start, should not be included
+        ef1 = EventFactory.create(EVENT_TYPE_SHOULD_NOT_COMMIT.getAnnotations(), EVENT_TYPE_SHOULD_NOT_COMMIT.getFields());
+
+        Event event1 = ef1.newEvent();
+
+        setEventValues(event1, ef1, EVENT_TYPE_SHOULD_NOT_COMMIT);
+        event1.commit();
+
+        r.start();
+        // Commit after start, should be included
+        ef2 = EventFactory.create(EVENT_TYPE_SHOULD_COMMIT.getAnnotations(),  EVENT_TYPE_SHOULD_COMMIT.getFields());
+
+        Event event2 = ef2.newEvent();
+        setEventValues(event2, ef2, EVENT_TYPE_SHOULD_COMMIT);
+        event2.commit();
+
+        r.stop();
+
+        RecordingFile es = Events.copyTo(r);
+        EventType e1 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_NOT_COMMIT.getName());
+        assertEquals(e1, ef1.getEventType());
+
+        EventType e2 = findEventType(es.readEventTypes(), EVENT_TYPE_SHOULD_COMMIT.getName());
+        assertEquals(e2, ef2.getEventType());
+
+        verifyEvent(es);
+    }
+
+    private static EventType findEventType(List<EventType> es, String name) {
+        for (EventType t : es) {
+            if (t.getName().equals(name)) {
+                return t;
+            }
+        }
+        throw new AssertionError("Could not find expected event type " + name);
+    }
+
+    private static void assertEquals(EventType e1, EventType expected) {
+        Asserts.assertEquals(e1.getName(), expected.getName());
+        Asserts.assertEquals(e1.getDescription(), expected.getDescription());
+        Asserts.assertEquals(e1.getLabel(), expected.getLabel());
+        assertValueDescriptorEquals(e1.getFields(), expected.getFields());
+        assertAnnotationEquals(e1.getAnnotationElements(), expected.getAnnotationElements());
+    }
+
+    private static void assertValueDescriptorEquals(List<ValueDescriptor> values, List<ValueDescriptor> expected) {
+        if (values.isEmpty() && expected.isEmpty()) {
+            return;
+        }
+
+        Map<String, ValueDescriptor> valueMap = new HashMap<>();
+        for (ValueDescriptor v : values) {
+            valueMap.put(v.getName(), v);
+        }
+        for (ValueDescriptor f : expected) {
+            ValueDescriptor v = valueMap.remove(f.getName());
+            if (v == null) {
+                throw new AssertionError("Expected value descriptor " + f.getName() + " not found");
+            }
+            assertEquals(v, f);
+        }
+        if (!valueMap.isEmpty()) {
+            throw new AssertionError("More fields than expected");
+        }
+    }
+
+    private static void assertEquals(ValueDescriptor v1, ValueDescriptor expected) {
+        Asserts.assertEquals(v1.getName(), expected.getName());
+        Asserts.assertEquals(v1.getTypeName(), expected.getTypeName());
+        assertAnnotationEquals(v1.getAnnotationElements(), expected.getAnnotationElements());
+    }
+
+    private static void assertAnnotationEquals(List<AnnotationElement> annotations, List<AnnotationElement> expected) {
+        annotations = new ArrayList<>(annotations); // make mutable
+        expected = new ArrayList<>(expected); // make mutable
+        class AnnotationTypeComparator implements Comparator<AnnotationElement> {
+            @Override
+            public int compare(AnnotationElement a, AnnotationElement b) {
+                return a.getTypeName().compareTo(b.getTypeName());
+            }
+        }
+
+        if (annotations.isEmpty() && expected.isEmpty()) {
+            return;
+        }
+
+        if (annotations.size() != expected.size()) {
+            System.out.println("Was:");
+            for(AnnotationElement ae: annotations) {
+                System.out.println(ae.getTypeName());
+            }
+            System.out.println("Expected:");
+            for(AnnotationElement ae: expected) {
+                System.out.println(ae.getTypeName());
+            }
+            throw new AssertionError("Wrong number of annotations");
+        }
+        Collections.sort(expected, new AnnotationTypeComparator());
+        Collections.sort(annotations, new AnnotationTypeComparator());
+        for (int i = 0; i < expected.size(); i++) {
+            assertEquals(annotations.get(i), expected.get(i));
+        }
+    }
+
+    private static void assertEquals(AnnotationElement a1, AnnotationElement expected) {
+        Asserts.assertEquals(a1.getTypeName(), expected.getTypeName());
+        // Don't recurse into annotation
+        assertValueDescriptorEquals(a1.getValueDescriptors(), expected.getValueDescriptors());
+    }
+
+    private static void verifyEvent(RecordingFile rf) throws IOException {
+        if (!rf.hasMoreEvents()) {
+            throw new AssertionError("Expected one dynamic event");
+        }
+        verifyValues(rf.readEvent());
+        if (rf.hasMoreEvents()) {
+            throw new AssertionError("Expected one dynamic event");
+        }
+    }
+
+    private static void setEventValues(Event event, EventFactory f, EventTypePrototype eventTypeProto) {
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            int index = eventTypeProto.getFieldIndex(entry.getKey());
+            event.set(index, entry.getValue());
+        }
+    }
+
+    private static void verifyValues(RecordedEvent event) {
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            String fieldName = entry.getKey();
+            Object value = event.getValue(fieldName);
+            Object expected = EVENT_VALUES.get(fieldName);
+            if (expected instanceof Class) {
+                value = ((RecordedClass) value).getName();
+                expected = ((Class<?>) expected).getName();
+            }
+            if (expected instanceof Thread) {
+                value = ((RecordedThread) value).getJavaName();
+                expected = ((Thread) expected).getName();
+            }
+            Asserts.assertEQ(value, expected);
+        }
+    }
+
+    private static EventTypePrototype makeEventType(String eventName) {
+        EventTypePrototype prototype = new EventTypePrototype(eventName);
+        prototype.addAnnotation(new AnnotationElement(TestAnnotation.class, "type"));
+        for (Map.Entry<String, Object> entry : EVENT_VALUES.entrySet()) {
+            Class<?> type = makePrimitive(entry.getValue().getClass());
+            String fieldName = entry.getKey();
+            prototype.addField(new ValueDescriptor(type, fieldName));
+        }
+        // add an annotated field
+        List<AnnotationElement> annos = new ArrayList<>();
+        annos.add(new AnnotationElement(TestAnnotation.class, "field"));
+        prototype.addField( new ValueDescriptor(int.class, "annotatedField", annos));
+
+        return prototype;
+    }
+
+    private static Class<?> makePrimitive(Class<? extends Object> clazz) {
+        if (clazz == Integer.class) {
+            return int.class;
+        }
+        if (clazz == Long.class) {
+            return long.class;
+        }
+        if (clazz == Double.class) {
+            return double.class;
+        }
+        if (clazz == Float.class) {
+            return float.class;
+        }
+        if (clazz == Short.class) {
+            return short.class;
+        }
+        if (clazz == Character.class) {
+            return char.class;
+        }
+        if (clazz == Byte.class) {
+            return byte.class;
+        }
+        if (clazz == Boolean.class) {
+            return boolean.class;
+        }
+        return clazz;
+    }
+}