| /******************************************************************************* |
| * Copyright (c) 2013, 2014 Ericsson |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Matthew Khouzam - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.ctf.core.tests.trace; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.fail; |
| |
| import java.nio.ByteOrder; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.UUID; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.ctf.core.CTFException; |
| import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration; |
| import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; |
| import org.eclipse.tracecompass.ctf.core.event.types.ISimpleDatatypeDeclaration; |
| import org.eclipse.tracecompass.ctf.core.tests.shared.CtfTestTraceUtils; |
| import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; |
| import org.eclipse.tracecompass.ctf.core.trace.ICTFStream; |
| import org.eclipse.tracecompass.ctf.core.trace.Metadata; |
| import org.eclipse.tracecompass.testtraces.ctf.CtfTestTrace; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import com.google.common.collect.Iterables; |
| |
| /** |
| * The class <code>MetadataTest</code> contains tests for the class |
| * <code>{@link Metadata}</code>. |
| * |
| * @author ematkho |
| * @version $Revision: 1.0 $ |
| */ |
| @SuppressWarnings("javadoc") |
| public class MetadataTest { |
| |
| private static final CtfTestTrace testTrace = CtfTestTrace.KERNEL; |
| private static final String mdStart = "typealias integer { size = 8; align = 8; signed = false; } := uint8_t;\n" + |
| " typealias integer { size = 16; align = 8; signed = false; } := uint16_t;\n" + |
| " typealias integer { size = 32; align = 8; signed = false; } := uint32_t;\n" + |
| " typealias integer { size = 64; align = 8; signed = false; } := uint64_t;\n" + |
| " typealias integer { size = 64; align = 8; signed = false; } := unsigned long;\n" + |
| " typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n" + |
| " typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n" + |
| "" + |
| " trace {\n" + |
| " major = 1;\n" + |
| " minor = 8;\n" + |
| " uuid = \"8b1258ba-effb-554b-b779-fbd676746000\";\n" + |
| " byte_order = le;\n" + |
| " packet.header := struct {\n" + |
| " uint32_t magic;\n" + |
| " uint8_t uuid[16];\n" + |
| " uint32_t stream_id;\n" + |
| " };\n" + |
| " };\n" + |
| "" + |
| " env {\n" + |
| " hostname = \"computer\";\n" + |
| " domain = \"kernel\";\n" + |
| " sysname = \"BeOS\";\n" + |
| " kernel_release = \"95\";\n" + |
| " kernel_version = \"BeWare 95\";\n" + |
| " tracer_name = \"BeOS Tracer\";\n" + |
| " tracer_major = 2;\n" + |
| " tracer_minor = 3;\n" + |
| " tracer_patchlevel = 0;\n" + |
| " };\n" + |
| " clock {\n" + |
| " name = monotonic;\n" + |
| " uuid = \"4d737a79-e3f1-4f4d-a649-42015266baf5\";\n" + |
| " description = \"Monotonic Clock\";\n" + |
| " freq = 1000000000; /* Frequency, in Hz */\n" + |
| " /* clock value offset from Epoch is: offset * (1/freq) */\n" + |
| " offset = 1383600210829415521;\n" + |
| " };\n" + |
| |
| " typealias integer {\n" + |
| "size = 27; align = 1; signed = false;\n" + |
| " map = clock.monotonic.value;\n" + |
| " } := uint27_clock_monotonic_t;\n" + |
| " \n" + |
| " typealias integer {\n" + |
| " size = 32; align = 8; signed = false;\n" + |
| " map = clock.monotonic.value;\n" + |
| " } := uint32_clock_monotonic_t;\n" + |
| " \n" + |
| " typealias integer {\n" + |
| " size = 64; align = 8; signed = false;\n" + |
| " map = clock.monotonic.value;\n" + |
| " } := uint64_clock_monotonic_t;\n" + |
| " \n" + |
| " struct packet_context {\n" + |
| " uint64_clock_monotonic_t timestamp_begin;\n" + |
| " uint64_clock_monotonic_t timestamp_end;\n" + |
| " uint64_t content_size;\n" + |
| " uint64_t packet_size;\n" + |
| " unsigned long events_discarded;\n" + |
| " uint32_t cpu_id;\n" + |
| " };\n" + |
| " \n" + |
| " struct event_header_compact {\n" + |
| " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n" + |
| " variant <id> {\n" + |
| " struct {\n" + |
| " uint27_clock_monotonic_t timestamp;\n" + |
| " } compact;\n" + |
| " struct {\n" + |
| " uint32_t id;\n" + |
| " uint64_clock_monotonic_t timestamp;\n" + |
| " } extended;\n" + |
| " } v;\n" + |
| " } align(8);\n" + |
| " \n" + |
| " struct event_header_large {\n" + |
| " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n" + |
| " variant <id> {\n" + |
| " struct {\n" + |
| " uint32_clock_monotonic_t timestamp;\n" + |
| " } compact;\n" + |
| " struct {\n" + |
| " uint32_t id;\n" + |
| " uint64_clock_monotonic_t timestamp;\n" + |
| " } extended;\n" + |
| " } v;\n" + |
| " } align(8);\n" + |
| " \n" + |
| " stream {\n" + |
| " id = 0;\n" + |
| " event.header := struct event_header_compact;\n" + |
| " packet.context := struct packet_context;\n" + |
| " };\n" + |
| " \n" + |
| " event {\n" + |
| " name = sched_switch;\n" + |
| " id = 0;\n" + |
| " stream_id = 0;\n" + |
| " fields := struct {\n" + |
| " integer { size = 8; align = 8; signed = 1; encoding = UTF8; base = 10; } _prev_comm[16];\n" + |
| " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _prev_tid;\n" + |
| " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _prev_prio;\n" + |
| " integer { size = 64; align = 8; signed = 1; encoding = none; base = 10; } _prev_state;\n" + |
| " integer { size = 8; align = 8; signed = 1; encoding = UTF8; base = 10; } _next_comm[16];\n" + |
| " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _next_tid;\n" + |
| " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _next_prio;\n" + |
| " };\n" + |
| " };"; |
| |
| private static final String mdSecond = " event {\n" + |
| " name = bozo_the_clown;\n" + |
| " id = 1;\n" + |
| " stream_id = 0;\n" + |
| " fields := struct {\n" + |
| " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } clown_nose;\n" + |
| " };\n" + |
| " };"; |
| |
| private static final String ENDIAN_CHANGE_L_B = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; byte_order = be; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = le; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| private static final String ENDIAN_CHANGE_L_N = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = le; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| private static final String ENDIAN_CHANGE_L_L = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; byte_order = le; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = le; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| |
| private static final String ENDIAN_CHANGE_B_L = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; byte_order = le; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = be; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| private static final String ENDIAN_CHANGE_B_N = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = be; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| private static final String ENDIAN_CHANGE_B_B = |
| "/* ctf 1.8 */" |
| + "typealias integer { size = 32; align = 16; byte_order = be; signed = true; base = dec; } := INT;" |
| + "trace { byte_order = be; };" |
| + "event { " |
| + " name = \"bob\"; " |
| + " fields := struct field { INT data ; };" |
| + "};"; |
| |
| |
| private Metadata fixture; |
| |
| /** |
| * Perform pre-test initialization. |
| * |
| * @throws CTFException |
| */ |
| @Before |
| public void setUp() throws CTFException { |
| fixture = new Metadata(CtfTestTraceUtils.getTrace(testTrace)); |
| } |
| |
| /** |
| * Run the Metadata(CTFTrace) constructor test. |
| */ |
| @Test |
| public void testMetadata() { |
| assertNotNull(fixture); |
| } |
| |
| @Test |
| public void testTextMD() throws CTFException { |
| testSingleFragment(); |
| } |
| |
| protected CTFTrace testSingleFragment() throws CTFException { |
| fixture = new Metadata(); |
| CTFTrace trace = fixture.getTrace(); |
| for (ICTFStream s : trace.getStreams()) { |
| fail("This should be empty, has" + s.toString()); |
| } |
| fixture.parseText(mdStart); |
| int count = 0; |
| for (ICTFStream s : trace.getStreams()) { |
| count++; |
| assertNotNull(s); |
| } |
| assertEquals(1, count); |
| assertEquals(1, trace.getEventDeclarations(0L).size()); |
| return trace; |
| } |
| |
| @Test |
| public void testStreamTextMD() throws CTFException { |
| CTFTrace trace = testSingleFragment(); |
| fixture.parseTextFragment(mdSecond); |
| final List<IEventDeclaration> eventDeclarations = new ArrayList<>(trace.getEventDeclarations(0L)); |
| assertEquals(2, eventDeclarations.size()); |
| assertEquals("bozo_the_clown", eventDeclarations.get(1).getName()); |
| } |
| |
| /** |
| * Run the ByteOrder getDetectedByteOrder() method test. |
| * |
| * @throws CTFException |
| */ |
| @Test |
| public void testGetDetectedByteOrder() throws CTFException { |
| setUp(); |
| ByteOrder result = fixture.getDetectedByteOrder(); |
| assertNull(result); |
| } |
| |
| /** |
| * Test toString |
| * |
| * @throws CTFException |
| */ |
| @Test |
| public void testToString() throws CTFException { |
| setUp(); |
| String result = fixture.toString(); |
| assertNotNull(result); |
| } |
| |
| /** |
| * Test a changing endian event field |
| * |
| * @throws CTFException |
| * won't happen |
| */ |
| @Test |
| public void testEndian() throws CTFException { |
| testEndianess(ENDIAN_CHANGE_L_B, ByteOrder.LITTLE_ENDIAN, ByteOrder.BIG_ENDIAN); |
| testEndianess(ENDIAN_CHANGE_L_N, ByteOrder.LITTLE_ENDIAN, ByteOrder.LITTLE_ENDIAN); |
| testEndianess(ENDIAN_CHANGE_L_L, ByteOrder.LITTLE_ENDIAN, ByteOrder.LITTLE_ENDIAN); |
| testEndianess(ENDIAN_CHANGE_B_L, ByteOrder.BIG_ENDIAN, ByteOrder.LITTLE_ENDIAN); |
| testEndianess(ENDIAN_CHANGE_B_N, ByteOrder.BIG_ENDIAN, ByteOrder.BIG_ENDIAN); |
| testEndianess(ENDIAN_CHANGE_B_B, ByteOrder.BIG_ENDIAN, ByteOrder.BIG_ENDIAN); |
| } |
| |
| private void testEndianess(String tsdl, ByteOrder traceEndian, ByteOrder fieldEndian) throws CTFException { |
| fixture = new Metadata(); |
| CTFTrace trace = fixture.getTrace(); |
| fixture.parseText(tsdl); |
| assertEquals(traceEndian, trace.getByteOrder()); |
| final Iterable<IEventDeclaration> eventDeclarations = trace.getEventDeclarations(0L); |
| assertNotNull(eventDeclarations); |
| IEventDeclaration event = Iterables.getFirst(eventDeclarations, null); |
| assertNotNull(event); |
| assertNotNull(event.getFields()); |
| final @Nullable IDeclaration field = event.getFields().getField("data"); |
| assertNotNull(field); |
| if (field instanceof ISimpleDatatypeDeclaration) { |
| ISimpleDatatypeDeclaration declaration = (ISimpleDatatypeDeclaration) field; |
| assertEquals(fieldEndian, declaration.getByteOrder()); |
| } else { |
| fail("data is not the right type"); |
| } |
| } |
| |
| /** |
| * Run the void parse() method test. |
| * |
| * @throws CTFException |
| */ |
| @Test |
| public void testParse() throws CTFException { |
| setUp(); |
| assertEquals(new UUID(0xd18e637435a1cd42L, 0x8e70a9cffa712793L), CtfTestTraceUtils.getTrace(testTrace).getUUID()); |
| assertEquals(1332166405241713920.0, CtfTestTraceUtils.getTrace(testTrace).getClock().getClockOffset(), 200.0); |
| assertEquals(8, CtfTestTraceUtils.getTrace(testTrace).getEnvironment().size()); |
| } |
| } |