Commit | Line | Data |
---|---|---|
b9780062 JG |
1 | #!/usr/bin/env python3 |
2 | # | |
3 | # Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
4 | # | |
5 | # SPDX-License-Identifier: GPL-2.0-only | |
6 | ||
b9780062 JG |
7 | import pathlib |
8 | import sys | |
9 | import os | |
10 | from typing import Any, Callable, Type, Dict, Iterator | |
11 | import random | |
12 | import string | |
13 | from collections.abc import Mapping | |
14 | ||
15 | """ | |
16 | Test the session commands of the `lttng` CLI client. | |
17 | """ | |
18 | ||
19 | # Import in-tree test utils | |
20 | test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils" | |
21 | sys.path.append(str(test_utils_import_path)) | |
22 | ||
23 | import lttngtest | |
24 | import bt2 | |
25 | ||
26 | ||
27 | class SessionSet(Mapping): | |
28 | def __init__(self, client, name_prefixes): | |
29 | self._sessions = {} # type dict[str, lttngtest.Session] | |
30 | for prefix in name_prefixes: | |
31 | new_session = client.create_session( | |
32 | name=self._generate_session_name_from_prefix(prefix), | |
33 | output=lttngtest.LocalSessionOutputLocation( | |
34 | test_env.create_temporary_directory("trace") | |
35 | ), | |
36 | ) | |
37 | # Add a channel to all sessions to ensure the sessions can be started. | |
38 | new_session.add_channel(lttngtest.TracingDomain.User) | |
39 | self._sessions[prefix] = new_session | |
40 | ||
41 | @staticmethod | |
42 | def _generate_session_name_from_prefix(prefix): | |
43 | # type: (str) -> str | |
44 | return ( | |
45 | prefix | |
46 | + "_" | |
47 | + "".join( | |
48 | random.choice(string.ascii_lowercase + string.digits) for _ in range(8) | |
49 | ) | |
50 | ) | |
51 | ||
52 | def __getitem__(self, __key): | |
53 | # type: (str) -> lttngtest.Session | |
54 | return self._sessions[__key] | |
55 | ||
56 | def __len__(self): | |
57 | # type: () -> int | |
58 | return len(self._sessions) | |
59 | ||
60 | def __iter__(self): | |
61 | # type: () -> Iterator[str] | |
62 | return iter(self._sessions) | |
63 | ||
64 | ||
65 | def test_start_globbing(tap, test_env): | |
66 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
67 | tap.diagnostic("Test --glob match of start command") | |
68 | name_prefixes = ["abba", "alakazou", "alakazam"] | |
69 | ||
70 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
71 | ||
72 | tap.diagnostic("Create a set of sessions to test globbing") | |
73 | sessions = None | |
74 | with tap.case( | |
75 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
76 | ) as test_case: | |
77 | sessions = SessionSet(client, name_prefixes) | |
78 | ||
79 | tap.test( | |
80 | all(not session.is_active for prefix, session in sessions.items()), | |
81 | "All sessions created are in the inactive state", | |
82 | ) | |
83 | ||
84 | start_pattern = "alak*" | |
85 | with tap.case("Start sessions with --glob={}".format(start_pattern)) as test_case: | |
86 | client.start_session_by_glob_pattern(start_pattern) | |
87 | ||
88 | tap.test( | |
89 | sessions["alakazou"].is_active | |
90 | and sessions["alakazam"].is_active | |
91 | and not sessions["abba"].is_active, | |
92 | "Only sessions 'alakazou' and 'alakazam' are active", | |
93 | ) | |
94 | ||
95 | with tap.case( | |
96 | "Starting already started sessions with --glob={} doesn't produce an error".format( | |
97 | start_pattern | |
98 | ) | |
99 | ) as test_case: | |
100 | client.start_session_by_glob_pattern(start_pattern) | |
101 | ||
102 | start_pattern = "tintina*" | |
103 | with tap.case( | |
104 | "Starting with --glob={} that doesn't match any session doesn't produce an error".format( | |
105 | start_pattern | |
106 | ) | |
107 | ) as test_case: | |
108 | client.start_session_by_glob_pattern(start_pattern) | |
109 | ||
110 | for name, session in sessions.items(): | |
111 | session.destroy() | |
112 | ||
113 | with tap.case( | |
114 | "Starting with --glob={} when no sessions exist doesn't produce an error".format( | |
115 | start_pattern | |
116 | ) | |
117 | ) as test_case: | |
118 | client.start_session_by_glob_pattern(start_pattern) | |
119 | ||
120 | ||
121 | def test_start_single(tap, test_env): | |
122 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
123 | tap.diagnostic("Test match of start command targeting a single session") | |
124 | name_prefixes = ["un", "deux", "patate", "pouel"] | |
125 | ||
126 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
127 | ||
128 | tap.diagnostic("Create a set of sessions to test single session start") | |
129 | sessions = None | |
130 | with tap.case( | |
131 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
132 | ) as test_case: | |
133 | sessions = SessionSet(client, name_prefixes) | |
134 | ||
135 | tap.test( | |
136 | all(not session.is_active for prefix, session in sessions.items()), | |
137 | "All sessions created are in the inactive state", | |
138 | ) | |
139 | ||
140 | session_to_start_prefix = "patate" | |
141 | full_session_name = sessions[session_to_start_prefix].name | |
142 | with tap.case("Start session '{}'".format(session_to_start_prefix)) as test_case: | |
143 | client.start_session_by_name(full_session_name) | |
144 | ||
145 | tap.test( | |
146 | any( | |
147 | session.is_active and prefix != session_to_start_prefix | |
148 | for prefix, session in sessions.items() | |
149 | ) | |
150 | is False, | |
151 | "Only session '{}' is active".format(session_to_start_prefix), | |
152 | ) | |
153 | ||
154 | with tap.case( | |
155 | "Starting already started session '{}' doesn't produce an error".format( | |
156 | session_to_start_prefix | |
157 | ) | |
158 | ) as test_case: | |
159 | client.start_session_by_name(full_session_name) | |
160 | ||
161 | for name, session in sessions.items(): | |
162 | session.destroy() | |
163 | ||
164 | ||
165 | def test_start_all(tap, test_env): | |
166 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
167 | tap.diagnostic("Test start command with the --all option") | |
168 | name_prefixes = ["a", "b", "c", "d"] | |
169 | ||
170 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
171 | ||
172 | tap.diagnostic("Create a set of sessions to test starting all sessions") | |
173 | sessions = None | |
174 | with tap.case( | |
175 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
176 | ) as test_case: | |
177 | sessions = SessionSet(client, name_prefixes) | |
178 | ||
179 | tap.test( | |
180 | all(not session.is_active for prefix, session in sessions.items()), | |
181 | "All sessions created are in the inactive state", | |
182 | ) | |
183 | ||
184 | with tap.case("Start all sessions") as test_case: | |
185 | client.start_sessions_all() | |
186 | ||
187 | tap.test( | |
188 | all(session.is_active for prefix, session in sessions.items()), | |
189 | "All sessions are active", | |
190 | ) | |
191 | ||
192 | with tap.case("Starting already started sessions") as test_case: | |
193 | client.start_sessions_all() | |
194 | ||
195 | for name, session in sessions.items(): | |
196 | session.destroy() | |
197 | ||
198 | with tap.case( | |
199 | "Starting all sessions when none exist doesn't produce an error" | |
200 | ) as test_case: | |
201 | client.start_sessions_all() | |
202 | ||
203 | ||
204 | def test_stop_globbing(tap, test_env): | |
205 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
206 | tap.diagnostic("Test --glob match of stop command") | |
207 | name_prefixes = ["East Farnham", "Amqui", "Amos"] | |
208 | ||
209 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
210 | ||
211 | tap.diagnostic("Create a set of sessions to test globbing") | |
212 | sessions = None | |
213 | with tap.case( | |
214 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
215 | ) as test_case: | |
216 | sessions = SessionSet(client, name_prefixes) | |
217 | ||
218 | client.start_sessions_all() | |
219 | tap.test( | |
220 | all(session.is_active for prefix, session in sessions.items()), | |
221 | "All sessions are in the active state", | |
222 | ) | |
223 | ||
224 | stop_pattern = "Am??i*" | |
225 | with tap.case("Stop sessions with --glob={}".format(stop_pattern)) as test_case: | |
226 | client.stop_session_by_glob_pattern(stop_pattern) | |
227 | ||
228 | tap.test( | |
229 | ( | |
230 | sessions["East Farnham"].is_active | |
231 | and sessions["Amos"].is_active | |
232 | and (not sessions["Amqui"].is_active) | |
233 | ), | |
234 | "Only session 'Amqui' is inactive", | |
235 | ) | |
236 | ||
237 | stop_pattern = "Am*" | |
238 | with tap.case( | |
239 | "Stopping more sessions, including a stopped session, with --glob={} doesn't produce an error".format( | |
240 | stop_pattern | |
241 | ) | |
242 | ) as test_case: | |
243 | client.stop_session_by_glob_pattern(stop_pattern) | |
244 | ||
245 | tap.test( | |
246 | sessions["East Farnham"].is_active | |
247 | and (not sessions["Amqui"].is_active) | |
248 | and (not sessions["Amos"].is_active), | |
249 | "Only session 'East Farnham' is active", | |
250 | ) | |
251 | ||
252 | stop_pattern = "Notre-Dame*" | |
253 | with tap.case( | |
254 | "Stopping with --glob={} that doesn't match any session doesn't produce an error".format( | |
255 | stop_pattern | |
256 | ) | |
257 | ) as test_case: | |
258 | client.stop_session_by_glob_pattern(stop_pattern) | |
259 | ||
260 | for name, session in sessions.items(): | |
261 | session.destroy() | |
262 | ||
263 | with tap.case( | |
264 | "Stopping with --glob={} when no sessions exist doesn't produce an error".format( | |
265 | stop_pattern | |
266 | ) | |
267 | ) as test_case: | |
268 | client.stop_session_by_glob_pattern(stop_pattern) | |
269 | ||
270 | ||
271 | def test_stop_single(tap, test_env): | |
272 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
273 | tap.diagnostic("Test match of stop command targeting a single session") | |
274 | name_prefixes = ["Grosses-Roches", "Kazabazua", "Laval", "Magog"] | |
275 | ||
276 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
277 | ||
278 | tap.diagnostic("Create a set of sessions to test single session stop") | |
279 | sessions = None | |
280 | with tap.case( | |
281 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
282 | ) as test_case: | |
283 | sessions = SessionSet(client, name_prefixes) | |
284 | ||
285 | client.start_sessions_all() | |
286 | tap.test( | |
287 | all(session.is_active for prefix, session in sessions.items()), | |
288 | "All sessions are in the active state", | |
289 | ) | |
290 | ||
291 | session_to_stop_prefix = "Kazabazua" | |
292 | full_session_name = sessions[session_to_stop_prefix].name | |
293 | with tap.case("Stop session '{}'".format(session_to_stop_prefix)) as test_case: | |
294 | client.stop_session_by_name(full_session_name) | |
295 | ||
296 | inactive_session_prefixes = [ | |
297 | prefix for prefix, session in sessions.items() if not session.is_active | |
298 | ] | |
299 | tap.test( | |
300 | len(inactive_session_prefixes) == 1 | |
301 | and inactive_session_prefixes[0] == session_to_stop_prefix, | |
302 | "Only session '{}' is inactive".format(session_to_stop_prefix), | |
303 | ) | |
304 | ||
305 | with tap.case( | |
306 | "Stopping already stopped session '{}' doesn't produce an error".format( | |
307 | session_to_stop_prefix | |
308 | ) | |
309 | ) as test_case: | |
310 | client.stop_session_by_name(full_session_name) | |
311 | ||
312 | for name, session in sessions.items(): | |
313 | session.destroy() | |
314 | ||
315 | ||
316 | def test_stop_all(tap, test_env): | |
317 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
318 | tap.diagnostic("Test stop command with the --all option") | |
319 | name_prefixes = ["a", "b", "c", "d"] | |
320 | ||
321 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
322 | ||
323 | tap.diagnostic("Create a set of sessions to test stopping all sessions") | |
324 | sessions = None | |
325 | with tap.case( | |
326 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
327 | ) as test_case: | |
328 | sessions = SessionSet(client, name_prefixes) | |
329 | ||
330 | client.start_sessions_all() | |
331 | tap.test( | |
332 | all(session.is_active for prefix, session in sessions.items()), | |
333 | "All sessions are in the active state", | |
334 | ) | |
335 | ||
336 | with tap.case("Stop all sessions") as test_case: | |
337 | client.stop_sessions_all() | |
338 | ||
339 | tap.test( | |
340 | all(not session.is_active for prefix, session in sessions.items()), | |
341 | "All sessions are inactive", | |
342 | ) | |
343 | ||
344 | with tap.case("Stopping already stopped sessions") as test_case: | |
345 | client.stop_sessions_all() | |
346 | ||
347 | for name, session in sessions.items(): | |
348 | session.destroy() | |
349 | ||
350 | with tap.case( | |
351 | "Stopping all sessions when none exist doesn't produce an error" | |
352 | ) as test_case: | |
353 | client.stop_sessions_all() | |
354 | ||
355 | ||
356 | def test_destroy_globbing(tap, test_env): | |
357 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
358 | tap.diagnostic("Test --glob match of destroy command") | |
359 | name_prefixes = ["Mont-Laurier", "Montreal", "Montmagny", "Neuville"] | |
360 | ||
361 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
362 | ||
363 | tap.diagnostic("Create a set of sessions to test globbing") | |
364 | sessions = None | |
365 | with tap.case( | |
366 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
367 | ) as test_case: | |
368 | sessions = SessionSet(client, name_prefixes) | |
369 | ||
370 | destroy_pattern = "Mont*" | |
371 | with tap.case( | |
372 | "Destroy sessions with --glob={}".format(destroy_pattern) | |
373 | ) as test_case: | |
374 | client.destroy_session_by_glob_pattern(destroy_pattern) | |
375 | ||
376 | listed_sessions = client.list_sessions() | |
377 | tap.test( | |
378 | len(listed_sessions) == 1 | |
379 | and listed_sessions[0].name == sessions["Neuville"].name, | |
380 | "Neuville is the only remaining session", | |
381 | ) | |
382 | ||
383 | for session in listed_sessions: | |
384 | session.destroy() | |
385 | ||
386 | with tap.case( | |
387 | "Destroying with --glob={} when no sessions exist doesn't produce an error".format( | |
388 | destroy_pattern | |
389 | ) | |
390 | ) as test_case: | |
391 | client.destroy_session_by_glob_pattern(destroy_pattern) | |
392 | ||
393 | ||
394 | def test_destroy_single(tap, test_env): | |
395 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
396 | tap.diagnostic("Test match of destroy command targeting a single session") | |
397 | name_prefixes = ["Natashquan", "Normetal", "Notre-Dame-des-Sept-Douleurs"] | |
398 | ||
399 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
400 | ||
401 | tap.diagnostic("Create a set of sessions to test single session destruction") | |
402 | sessions = None | |
403 | with tap.case( | |
404 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
405 | ) as test_case: | |
406 | sessions = SessionSet(client, name_prefixes) | |
407 | ||
408 | session_to_destroy_prefix = "Normetal" | |
409 | full_session_name = sessions[session_to_destroy_prefix].name | |
410 | with tap.case( | |
411 | "Destroy session '{}'".format(session_to_destroy_prefix) | |
412 | ) as test_case: | |
413 | client.destroy_session_by_name(full_session_name) | |
414 | ||
415 | listed_sessions = client.list_sessions() | |
416 | tap.test( | |
417 | len(listed_sessions) == 2 | |
418 | and full_session_name not in [session.name for session in listed_sessions], | |
419 | "Session '{}' no longer exists".format(session_to_destroy_prefix), | |
420 | ) | |
421 | ||
422 | for session in listed_sessions: | |
423 | session.destroy() | |
424 | ||
425 | ||
426 | def test_destroy_all(tap, test_env): | |
427 | # type: (lttngtest.TapGenerator, lttngtest._Environment) -> None | |
428 | tap.diagnostic("Test destroy command with the --all option") | |
429 | name_prefixes = ["a", "b", "c", "d"] | |
430 | ||
431 | client = lttngtest.LTTngClient(test_env, log=tap.diagnostic) | |
432 | ||
433 | tap.diagnostic("Create a set of sessions to test destroying all sessions") | |
434 | sessions = None | |
435 | with tap.case( | |
436 | "Create sessions with prefixes [{}]".format(", ".join(name_prefixes)) | |
437 | ) as test_case: | |
438 | sessions = SessionSet(client, name_prefixes) | |
439 | ||
440 | with tap.case("Destroy all sessions") as test_case: | |
441 | client.destroy_sessions_all() | |
442 | ||
443 | tap.test( | |
444 | len(client.list_sessions()) == 0, | |
445 | "No sessions exist after destroying all sessions", | |
446 | ) | |
447 | ||
448 | with tap.case( | |
449 | "Destroy all sessions when none exist doesn't produce an error" | |
450 | ) as test_case: | |
451 | client.destroy_sessions_all() | |
452 | ||
453 | ||
454 | tap = lttngtest.TapGenerator(48) | |
455 | tap.diagnostic("Test client session command --glob and --all options") | |
456 | ||
457 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
458 | test_start_globbing(tap, test_env) | |
459 | ||
460 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
461 | test_start_single(tap, test_env) | |
462 | ||
463 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
464 | test_start_all(tap, test_env) | |
465 | ||
466 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
467 | test_stop_globbing(tap, test_env) | |
468 | ||
469 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
470 | test_stop_single(tap, test_env) | |
471 | ||
472 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
473 | test_stop_all(tap, test_env) | |
474 | ||
475 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
476 | test_destroy_globbing(tap, test_env) | |
477 | ||
478 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
479 | test_destroy_single(tap, test_env) | |
480 | ||
481 | with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env: | |
482 | test_destroy_all(tap, test_env) | |
483 | ||
484 | sys.exit(0 if tap.is_successful else 1) |