f972c44bbb18e723667c2bb493d697f8b6e3b3e6
[lttng-tools.git] / tests / unit / test_session.cpp
1 /*
2 * Copyright (C) 2011 EfficiOS Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include <common/common.hpp>
9 #include <common/compat/errno.hpp>
10 #include <common/sessiond-comm/sessiond-comm.hpp>
11
12 #include <bin/lttng-sessiond/health-sessiond.hpp>
13 #include <bin/lttng-sessiond/session.hpp>
14 #include <bin/lttng-sessiond/thread.hpp>
15 #include <bin/lttng-sessiond/ust-app.hpp>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <tap/tap.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <urcu.h>
24
25 #define SESSION1 "test1"
26
27 #define MAX_SESSIONS 10000
28 #define RANDOM_STRING_LEN 11
29
30 /* Number of TAP tests in this file */
31 #define NUM_TESTS 11
32
33 static struct ltt_session_list *session_list;
34
35 static const char alphanum[] = "0123456789"
36 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
37 "abcdefghijklmnopqrstuvwxyz";
38 static char random_string[RANDOM_STRING_LEN];
39
40 /*
41 * Return random string of 10 characters.
42 * Not thread-safe.
43 */
44 static char *get_random_string()
45 {
46 int i;
47
48 for (i = 0; i < RANDOM_STRING_LEN - 1; i++) {
49 random_string[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
50 }
51
52 random_string[RANDOM_STRING_LEN - 1] = '\0';
53
54 return random_string;
55 }
56
57 /*
58 * Return 0 if session name is found, else -1
59 */
60 static int find_session_name(const char *name)
61 {
62 struct ltt_session *iter;
63
64 cds_list_for_each_entry (iter, &session_list->head, list) {
65 if (strcmp(iter->name, name) == 0) {
66 return 0;
67 }
68 }
69
70 return -1;
71 }
72
73 static int session_list_count()
74 {
75 int count = 0;
76 struct ltt_session *iter;
77
78 cds_list_for_each_entry (iter, &session_list->head, list) {
79 count++;
80 }
81 return count;
82 }
83
84 /*
85 * Empty session list manually.
86 */
87 static void empty_session_list()
88 {
89 struct ltt_session *iter, *tmp;
90
91 const auto list_lock = lttng::sessiond::lock_session_list();
92 cds_list_for_each_entry_safe (iter, tmp, &session_list->head, list) {
93 session_destroy(iter);
94 }
95
96 /* Session list must be 0 */
97 LTTNG_ASSERT(!session_list_count());
98 }
99
100 /*
101 * Test creation of 1 session
102 */
103 static int create_one_session(const char *name)
104 {
105 int ret;
106 enum lttng_error_code ret_code;
107 struct ltt_session *session = nullptr;
108
109 const auto list_lock = lttng::sessiond::lock_session_list();
110 ret_code = session_create(name, geteuid(), getegid(), &session);
111 session_put(session);
112 if (ret_code == LTTNG_OK) {
113 /* Validate */
114 ret = find_session_name(name);
115 if (ret < 0) {
116 /* Session not found by name */
117 printf("session not found after creation\n");
118 ret = -1;
119 } else {
120 /* Success */
121 ret = 0;
122 }
123 } else {
124 if (ret_code == LTTNG_ERR_EXIST_SESS) {
125 printf("(session already exists) ");
126 }
127 ret = -1;
128 }
129
130 return ret;
131 }
132
133 /*
134 * Test deletion of 1 session
135 */
136 static int destroy_one_session(ltt_session::ref session)
137 {
138 int ret;
139 char session_name[NAME_MAX];
140
141 strncpy(session_name, session->name, sizeof(session_name));
142 session_name[sizeof(session_name) - 1] = '\0';
143
144 /* Reference of the session list. */
145 ltt_session *weak_session_ptr = &session.get();
146 {
147 /* Drop the reference that stems from the look-up. */
148 const ltt_session::ref reference_to_drop = std::move(session);
149 }
150
151 session_destroy(weak_session_ptr);
152
153 ret = find_session_name(session_name);
154 if (ret < 0) {
155 /* Success, -1 means that the sesion is NOT found */
156 ret = 0;
157 } else {
158 /* Fail */
159 ret = -1;
160 }
161
162 return ret;
163 }
164
165 /*
166 * This test is supposed to fail at the second create call. If so, return 0 for
167 * test success, else -1.
168 */
169 static int two_session_same_name()
170 {
171 const auto ret = create_one_session(SESSION1);
172 if (ret < 0) {
173 /* Fail */
174 return -1;
175 }
176
177 /*
178 * Mind the order of the declaration of list_lock vs session:
179 * the session list lock must always be released _after_ the release of
180 * a session's reference (the destruction of a ref/locked_ref) to ensure
181 * since the reference's release may unpublish the session from the list of
182 * sessions.
183 */
184 const auto list_lock = lttng::sessiond::lock_session_list();
185 try {
186 const auto session = ltt_session::find_session(SESSION1);
187 /* Success */
188 return 0;
189 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
190 /* Fail */
191 return -1;
192 }
193 }
194
195 static void test_session_list()
196 {
197 session_list = session_get_list();
198 ok(session_list != nullptr, "Session list: not NULL");
199 }
200
201 static void test_create_one_session()
202 {
203 ok(create_one_session(SESSION1) == 0, "Create session: %s", SESSION1);
204 }
205
206 static void test_validate_session()
207 {
208 /*
209 * Mind the order of the declaration of list_lock vs session:
210 * the session list lock must always be released _after_ the release of
211 * a session's reference (the destruction of a ref/locked_ref) to ensure
212 * since the reference's release may unpublish the session from the list of
213 * sessions.
214 */
215 const auto list_lock = lttng::sessiond::lock_session_list();
216
217 try {
218 const auto session = ltt_session::find_session(SESSION1);
219 pass("Validating session: session found");
220
221 ok(session->kernel_session == nullptr && strlen(session->name),
222 "Validating session: basic sanity check");
223
224 session->lock();
225 session->unlock();
226 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
227 fail("Validating session: session found");
228 skip(1, "Skipping session validation check as session was not found");
229 }
230 }
231
232 static void test_destroy_session()
233 {
234 /*
235 * Mind the order of the declaration of list_lock vs session:
236 * the session list lock must always be released _after_ the release of
237 * a session's reference (the destruction of a ref/locked_ref) to ensure
238 * since the reference's release may unpublish the session from the list of
239 * sessions.
240 */
241 const auto list_lock = lttng::sessiond::lock_session_list();
242
243 try {
244 auto session = ltt_session::find_session(SESSION1);
245
246 pass("Destroying session: session found");
247
248 ok(destroy_one_session(std::move(session)) == 0,
249 "Destroying session: %s destroyed",
250 SESSION1);
251
252 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
253 fail("Destroying session: session found");
254 skip(1, "Skipping session destruction as it was not found");
255 }
256 }
257
258 static void test_duplicate_session()
259 {
260 ok(two_session_same_name() == 0, "Duplicate session creation");
261 }
262
263 static void test_session_name_generation()
264 {
265 struct ltt_session *session = nullptr;
266 enum lttng_error_code ret_code;
267 const char *expected_session_name_prefix = DEFAULT_SESSION_NAME;
268
269 const auto list_lock = lttng::sessiond::lock_session_list();
270
271 ret_code = session_create(nullptr, geteuid(), getegid(), &session);
272 ok(ret_code == LTTNG_OK, "Create session with a NULL name (auto-generate a name)");
273 if (!session) {
274 skip(1, "Skipping session name generation tests as session_create() failed.");
275 goto end;
276 }
277 diag("Automatically-generated session name: %s", *session->name ? session->name : "ERROR");
278 ok(*session->name &&
279 !strncmp(expected_session_name_prefix,
280 session->name,
281 sizeof(DEFAULT_SESSION_NAME) - 1),
282 "Auto-generated session name starts with %s",
283 DEFAULT_SESSION_NAME);
284 end:
285 session_put(session);
286 }
287
288 static void test_large_session_number()
289 {
290 int ret, i, failed = 0;
291 struct ltt_session *iter, *tmp;
292
293 for (i = 0; i < MAX_SESSIONS; i++) {
294 char *tmp_name = get_random_string();
295 ret = create_one_session(tmp_name);
296 if (ret < 0) {
297 diag("session %d (name: %s) creation failed", i, tmp_name);
298 ++failed;
299 }
300 }
301
302 ok(failed == 0, "Large sessions number: created %u sessions", MAX_SESSIONS);
303
304 failed = 0;
305
306 const auto list_lock = lttng::sessiond::lock_session_list();
307 for (i = 0; i < MAX_SESSIONS; i++) {
308 cds_list_for_each_entry_safe (iter, tmp, &session_list->head, list) {
309 ret = destroy_one_session([iter]() {
310 session_get(iter);
311 return ltt_session::ref(*iter);
312 }());
313
314 if (ret < 0) {
315 diag("session %d destroy failed", i);
316 ++failed;
317 }
318 }
319 }
320
321 ok(failed == 0 && session_list_count() == 0,
322 "Large sessions number: destroyed %u sessions",
323 MAX_SESSIONS);
324 }
325
326 int main()
327 {
328 plan_tests(NUM_TESTS);
329
330 the_health_sessiond = health_app_create(NR_HEALTH_SESSIOND_TYPES);
331
332 diag("Sessions unit tests");
333
334 rcu_register_thread();
335
336 test_session_list();
337
338 test_create_one_session();
339
340 test_validate_session();
341
342 test_destroy_session();
343
344 test_duplicate_session();
345
346 empty_session_list();
347
348 test_session_name_generation();
349
350 test_large_session_number();
351
352 rcu_unregister_thread();
353 lttng_thread_list_shutdown_orphans();
354
355 return exit_status();
356 }
This page took 0.036578 seconds and 3 git commands to generate.