Commit | Line | Data |
---|---|---|
5df9e303 JG |
1 | #!/usr/bin/env python3 |
2 | # | |
3 | # The MIT License (MIT) | |
4 | # | |
5 | # Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
6 | # | |
7 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | # of this software and associated documentation files (the "Software"), to deal | |
9 | # in the Software without restriction, including without limitation the rights | |
10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | # copies of the Software, and to permit persons to whom the Software is | |
12 | # furnished to do so, subject to the following conditions: | |
13 | # | |
14 | # The above copyright notice and this permission notice shall be included in | |
15 | # all copies or substantial portions of the Software. | |
16 | # | |
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 | # SOFTWARE. | |
24 | ||
25 | import bt_python_helper | |
26 | import tempfile | |
27 | import babeltrace.writer as btw | |
28 | import babeltrace.reader as btr | |
29 | import uuid | |
30 | import shutil | |
31 | ||
32 | ||
33 | class Entry(object): | |
34 | def __init__(self, stream_id, timestamp=None, end_of_packet=False): | |
35 | self.stream_id = stream_id | |
36 | self.timestamp = timestamp | |
37 | self.end_of_packet = end_of_packet | |
38 | ||
39 | ||
40 | class Packet(object): | |
41 | def __init__(self, timestamps): | |
42 | self.timestamps = timestamps | |
43 | ||
44 | clock_uuid = uuid.uuid4() | |
45 | ||
46 | # stream_descriptions is a list of lists of Packets. | |
47 | # Each stream description list is mapped to a single stream instance. | |
48 | def create_trace(path, clock_uuid, stream_descriptions): | |
49 | trace = btw.Writer(path) | |
50 | clock = btw.Clock('test_clock') | |
51 | clock.uuid = clock_uuid | |
52 | trace.add_clock(clock) | |
53 | ||
54 | integer_field_type = btw.IntegerFieldDeclaration(32) | |
55 | ||
56 | event_class = btw.EventClass('simple_event') | |
57 | event_class.add_field(integer_field_type, 'int_field') | |
58 | ||
59 | stream_class = btw.StreamClass('test_stream') | |
60 | stream_class.add_event_class(event_class) | |
61 | stream_class.clock = clock | |
62 | ||
63 | streams = [] | |
64 | stream_entries = [] | |
65 | for stream_id, stream_packets in enumerate(stream_descriptions): | |
66 | stream = trace.create_stream(stream_class) | |
67 | streams.append(stream) | |
68 | ||
69 | for packet in stream_packets: | |
70 | for timestamp in packet.timestamps: | |
71 | stream_entries.append(Entry(stream_id, timestamp)) | |
72 | # Mark the last inserted entry as the end of packet | |
73 | stream_entries[len(stream_entries) - 1].end_of_packet = True | |
74 | ||
75 | # Sort stream entries which will provide us with a time-ordered list of | |
76 | # events to insert in the streams. | |
77 | for entry in sorted(stream_entries, key=lambda entry: entry.timestamp): | |
78 | clock.time = entry.timestamp | |
79 | event = btw.Event(event_class) | |
80 | event.payload('int_field').value = entry.stream_id | |
81 | streams[entry.stream_id].append_event(event) | |
82 | if entry.end_of_packet is True: | |
83 | streams[entry.stream_id].flush() | |
84 | ||
85 | ||
86 | def check_trace_expected_timestamps(trace_paths, expected_timestamps): | |
87 | traces = btr.TraceCollection(intersect_mode=True) | |
88 | for trace_path in trace_paths: | |
89 | trace_handle = traces.add_trace(trace_path, 'ctf') | |
90 | if trace_handle is None: | |
91 | print('Failed to open trace at {}'.format(trace_path)) | |
92 | return False | |
93 | for event in traces.events: | |
94 | expected_timestamp = expected_timestamps.pop(0) | |
95 | if event.timestamp != expected_timestamp: | |
96 | print('# Unexpected timestamp ({}), expected {}'.format( | |
97 | event.timestamp, expected_timestamp)) | |
98 | return False | |
99 | return True | |
100 | ||
101 | ||
102 | def print_test_result(test_number, result, description): | |
103 | result_string = 'ok' if result else 'not ok' | |
104 | result_string += ' {} - {}'.format(test_number, description) | |
105 | print(result_string) | |
106 | ||
107 | TEST_COUNT = 3 | |
108 | # TAP plan | |
109 | print('1..{}'.format(TEST_COUNT)) | |
110 | ||
111 | trace_path_early = tempfile.mkdtemp() | |
112 | ||
113 | # The stream intersection of this trace is event timestamps 11, 12 and 13, | |
114 | # accounting for 9 events in stream-intersection mode | |
115 | print('# Creating early trace at {}'.format(trace_path_early)) | |
116 | create_trace(trace_path_early, clock_uuid, [ | |
117 | [Packet(range(1, 7)), Packet(range(11, 18))], | |
118 | [Packet(range(8, 15)), Packet(range(22, 24)), Packet(range(30, 60))], | |
119 | [Packet(range(11, 14))] | |
120 | ]) | |
121 | ||
122 | trace_path_late = tempfile.mkdtemp() | |
123 | print('# Creating late trace at {}'.format(trace_path_late)) | |
124 | # The stream intersection of this trace is event timestamps 100, 101, 102, 103 | |
125 | # and 104 accounting for 15 events in stream-intersection mode | |
126 | create_trace(trace_path_late, clock_uuid, [ | |
127 | [Packet(range(100, 105)), Packet(range(109, 120))], | |
128 | [Packet(range(88, 95)), Packet(range(96, 110)), Packet(range(112, 140))], | |
129 | [Packet(range(99, 105))] | |
130 | ]) | |
131 | ||
132 | expected_timestamps_early = [] | |
133 | for ts in range(11, 14): | |
134 | for stream in range(3): | |
135 | expected_timestamps_early.append(ts) | |
136 | ||
137 | expected_timestamps_late = [] | |
138 | for ts in range(100, 105): | |
139 | for stream in range(3): | |
140 | expected_timestamps_late.append(ts) | |
141 | ||
142 | expected_timestamps_union = (expected_timestamps_early + | |
143 | expected_timestamps_late) | |
144 | ||
145 | # Validate that the stream-intersection mode on a single trace returns only | |
146 | # the events that are in overlapping packets across all of the trace's streams. | |
147 | result = check_trace_expected_timestamps([trace_path_early], | |
148 | expected_timestamps_early) | |
149 | print_test_result(1, result, 'Validating expected event timestamps of "early" trace') | |
150 | ||
151 | result = check_trace_expected_timestamps([trace_path_late], | |
152 | expected_timestamps_late) | |
153 | print_test_result(2, result, 'Validating expected event timestamps of "late" trace') | |
154 | ||
155 | result = check_trace_expected_timestamps([trace_path_early, trace_path_late], | |
156 | expected_timestamps_union) | |
157 | print_test_result(3, result, 'Validating expected event timestamps of the union of "early" and "late" traces') | |
158 | ||
159 | shutil.rmtree(trace_path_early) | |
160 | shutil.rmtree(trace_path_late) |