sessiond: introduce ltt_session::locked_ref look-up functions
[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(struct ltt_session *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 session_destroy(session);
145 session_put(session);
146
147 ret = find_session_name(session_name);
148 if (ret < 0) {
149 /* Success, -1 means that the sesion is NOT found */
150 ret = 0;
151 } else {
152 /* Fail */
153 ret = -1;
154 }
155
156 return ret;
157 }
158
159 /*
160 * This test is supposed to fail at the second create call. If so, return 0 for
161 * test success, else -1.
162 */
163 static int two_session_same_name()
164 {
165 const auto ret = create_one_session(SESSION1);
166 if (ret < 0) {
167 /* Fail */
168 return -1;
169 }
170
171 /*
172 * Mind the order of the declaration of list_lock vs session:
173 * the session list lock must always be released _after_ the release of
174 * a session's reference (the destruction of a ref/locked_ref) to ensure
175 * since the reference's release may unpublish the session from the list of
176 * sessions.
177 */
178 const auto list_lock = lttng::sessiond::lock_session_list();
179 try {
180 const auto session = ltt_session::find_session(SESSION1);
181 /* Success */
182 return 0;
183 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
184 /* Fail */
185 return -1;
186 }
187 }
188
189 static void test_session_list()
190 {
191 session_list = session_get_list();
192 ok(session_list != nullptr, "Session list: not NULL");
193 }
194
195 static void test_create_one_session()
196 {
197 ok(create_one_session(SESSION1) == 0, "Create session: %s", SESSION1);
198 }
199
200 static void test_validate_session()
201 {
202 /*
203 * Mind the order of the declaration of list_lock vs session:
204 * the session list lock must always be released _after_ the release of
205 * a session's reference (the destruction of a ref/locked_ref) to ensure
206 * since the reference's release may unpublish the session from the list of
207 * sessions.
208 */
209 const auto list_lock = lttng::sessiond::lock_session_list();
210 ltt_session::ref session;
211
212 try {
213 session = ltt_session::find_session(SESSION1);
214 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
215 }
216
217 ok(session, "Validating session: session found");
218
219 if (session) {
220 ok(session->kernel_session == nullptr && strlen(session->name),
221 "Validating session: basic sanity check");
222 } else {
223 skip(1, "Skipping session validation check as session was not found");
224 return;
225 }
226
227 session->lock();
228 session->unlock();
229 }
230
231 static void test_destroy_session()
232 {
233 /*
234 * Mind the order of the declaration of list_lock vs session:
235 * the session list lock must always be released _after_ the release of
236 * a session's reference (the destruction of a ref/locked_ref) to ensure
237 * since the reference's release may unpublish the session from the list of
238 * sessions.
239 */
240 const auto list_lock = lttng::sessiond::lock_session_list();
241 ltt_session::ref session;
242
243 try {
244 session = ltt_session::find_session(SESSION1);
245 } catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
246 }
247
248 ok(session, "Destroying session: session found");
249
250 if (session) {
251 ok(destroy_one_session(session.release()) == 0,
252 "Destroying session: %s destroyed",
253 SESSION1);
254 } else {
255 skip(1, "Skipping session destruction as it was not found");
256 }
257 }
258
259 static void test_duplicate_session()
260 {
261 ok(two_session_same_name() == 0, "Duplicate session creation");
262 }
263
264 static void test_session_name_generation()
265 {
266 struct ltt_session *session = nullptr;
267 enum lttng_error_code ret_code;
268 const char *expected_session_name_prefix = DEFAULT_SESSION_NAME;
269
270 const auto list_lock = lttng::sessiond::lock_session_list();
271
272 ret_code = session_create(nullptr, geteuid(), getegid(), &session);
273 ok(ret_code == LTTNG_OK, "Create session with a NULL name (auto-generate a name)");
274 if (!session) {
275 skip(1, "Skipping session name generation tests as session_create() failed.");
276 goto end;
277 }
278 diag("Automatically-generated session name: %s", *session->name ? session->name : "ERROR");
279 ok(*session->name &&
280 !strncmp(expected_session_name_prefix,
281 session->name,
282 sizeof(DEFAULT_SESSION_NAME) - 1),
283 "Auto-generated session name starts with %s",
284 DEFAULT_SESSION_NAME);
285 end:
286 session_put(session);
287 }
288
289 static void test_large_session_number()
290 {
291 int ret, i, failed = 0;
292 struct ltt_session *iter, *tmp;
293
294 for (i = 0; i < MAX_SESSIONS; i++) {
295 char *tmp_name = get_random_string();
296 ret = create_one_session(tmp_name);
297 if (ret < 0) {
298 diag("session %d (name: %s) creation failed", i, tmp_name);
299 ++failed;
300 }
301 }
302
303 ok(failed == 0, "Large sessions number: created %u sessions", MAX_SESSIONS);
304
305 failed = 0;
306
307 const auto list_lock = lttng::sessiond::lock_session_list();
308 for (i = 0; i < MAX_SESSIONS; i++) {
309 cds_list_for_each_entry_safe (iter, tmp, &session_list->head, list) {
310 LTTNG_ASSERT(session_get(iter));
311 ret = destroy_one_session(iter);
312 if (ret < 0) {
313 diag("session %d destroy failed", i);
314 ++failed;
315 }
316 }
317 }
318
319 ok(failed == 0 && session_list_count() == 0,
320 "Large sessions number: destroyed %u sessions",
321 MAX_SESSIONS);
322 }
323
324 int main()
325 {
326 plan_tests(NUM_TESTS);
327
328 the_health_sessiond = health_app_create(NR_HEALTH_SESSIOND_TYPES);
329
330 diag("Sessions unit tests");
331
332 rcu_register_thread();
333
334 test_session_list();
335
336 test_create_one_session();
337
338 test_validate_session();
339
340 test_destroy_session();
341
342 test_duplicate_session();
343
344 empty_session_list();
345
346 test_session_name_generation();
347
348 test_large_session_number();
349
350 rcu_unregister_thread();
351 lttng_thread_list_shutdown_orphans();
352
353 return exit_status();
354 }
This page took 0.036119 seconds and 4 git commands to generate.