source: mainline/uspace/lib/system/test/system.c@ 3951046

Last change on this file since 3951046 was f35749e, checked in by Jiri Svoboda <jiri@…>, 4 months ago

System restart via shutdown -r

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <async.h>
30#include <errno.h>
31#include <fibril_synch.h>
32#include <loc.h>
33#include <pcut/pcut.h>
34#include <str.h>
35#include <system.h>
36#include <system_srv.h>
37#include "../private/system.h"
38
39PCUT_INIT;
40
41PCUT_TEST_SUITE(system);
42
43static const char *test_system_server = "test-system";
44static const char *test_system_svc = "test/system";
45
46void test_system_conn(ipc_call_t *, void *);
47
48static errno_t test_poweroff(void *);
49static errno_t test_restart(void *);
50
51static void test_sys_shutdown_complete(void *);
52static void test_sys_shutdown_failed(void *);
53
54static system_ops_t test_system_srv_ops = {
55 .poweroff = test_poweroff,
56 .restart = test_restart
57};
58
59system_cb_t test_system_cb = {
60 .shutdown_complete = test_sys_shutdown_complete,
61 .shutdown_failed = test_sys_shutdown_failed
62};
63
64/** Describes to the server how to respond to our request and pass tracking
65 * data back to the client.
66 */
67typedef struct {
68 errno_t rc;
69
70 bool poweroff_called;
71 bool restart_called;
72 bool shutdown_complete_called;
73 bool shutdown_failed_called;
74
75 fibril_condvar_t event_cv;
76 fibril_mutex_t event_lock;
77 system_srv_t *srv;
78} test_response_t;
79
80/** system_open(), system_close() work for valid system control service */
81PCUT_TEST(open_close)
82{
83 errno_t rc;
84 service_id_t sid;
85 system_t *system = NULL;
86 test_response_t resp;
87 loc_srv_t *srv;
88
89 async_set_fallback_port_handler(test_system_conn, &resp);
90
91 // FIXME This causes this test to be non-reentrant!
92 rc = loc_server_register(test_system_server, &srv);
93 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
94
95 rc = loc_service_register(srv, test_system_svc, &sid);
96 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
97
98 rc = system_open(test_system_svc, NULL, NULL, &system);
99 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
100 PCUT_ASSERT_NOT_NULL(system);
101
102 system_close(system);
103 rc = loc_service_unregister(srv, sid);
104 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
105 loc_server_unregister(srv);
106}
107
108/** system_poweroff() with server returning error response works */
109PCUT_TEST(poweroff_failure)
110{
111 errno_t rc;
112 service_id_t sid;
113 system_t *system = NULL;
114 test_response_t resp;
115 loc_srv_t *srv;
116
117 async_set_fallback_port_handler(test_system_conn, &resp);
118
119 // FIXME This causes this test to be non-reentrant!
120 rc = loc_server_register(test_system_server, &srv);
121 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
122
123 rc = loc_service_register(srv, test_system_svc, &sid);
124 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
125
126 rc = system_open(test_system_svc, NULL, NULL, &system);
127 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
128 PCUT_ASSERT_NOT_NULL(system);
129
130 resp.rc = ENOMEM;
131 resp.poweroff_called = false;
132
133 rc = system_poweroff(system);
134 PCUT_ASSERT_TRUE(resp.poweroff_called);
135 PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
136
137 system_close(system);
138 rc = loc_service_unregister(srv, sid);
139 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
140 loc_server_unregister(srv);
141}
142
143/** system_poweroff() with server returning success response works */
144PCUT_TEST(poweroff_success)
145{
146 errno_t rc;
147 service_id_t sid;
148 system_t *system = NULL;
149 test_response_t resp;
150 loc_srv_t *srv;
151
152 async_set_fallback_port_handler(test_system_conn, &resp);
153
154 // FIXME This causes this test to be non-reentrant!
155 rc = loc_server_register(test_system_server, &srv);
156 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
157
158 rc = loc_service_register(srv, test_system_svc, &sid);
159 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
160
161 rc = system_open(test_system_svc, NULL, NULL, &system);
162 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
163 PCUT_ASSERT_NOT_NULL(system);
164
165 resp.rc = EOK;
166 resp.poweroff_called = false;
167
168 rc = system_poweroff(system);
169 PCUT_ASSERT_TRUE(resp.poweroff_called);
170 PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
171
172 system_close(system);
173 rc = loc_service_unregister(srv, sid);
174 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
175 loc_server_unregister(srv);
176}
177
178/** system_restart() with server returning error response works */
179PCUT_TEST(restart_failure)
180{
181 errno_t rc;
182 service_id_t sid;
183 system_t *system = NULL;
184 test_response_t resp;
185 loc_srv_t *srv;
186
187 async_set_fallback_port_handler(test_system_conn, &resp);
188
189 // FIXME This causes this test to be non-reentrant!
190 rc = loc_server_register(test_system_server, &srv);
191 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
192
193 rc = loc_service_register(srv, test_system_svc, &sid);
194 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
195
196 rc = system_open(test_system_svc, NULL, NULL, &system);
197 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
198 PCUT_ASSERT_NOT_NULL(system);
199
200 resp.rc = ENOMEM;
201 resp.restart_called = false;
202
203 rc = system_restart(system);
204 PCUT_ASSERT_TRUE(resp.restart_called);
205 PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
206
207 system_close(system);
208 rc = loc_service_unregister(srv, sid);
209 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
210 loc_server_unregister(srv);
211}
212
213/** system_restart() with server returning success response works */
214PCUT_TEST(restart_success)
215{
216 errno_t rc;
217 service_id_t sid;
218 system_t *system = NULL;
219 test_response_t resp;
220 loc_srv_t *srv;
221
222 async_set_fallback_port_handler(test_system_conn, &resp);
223
224 // FIXME This causes this test to be non-reentrant!
225 rc = loc_server_register(test_system_server, &srv);
226 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
227
228 rc = loc_service_register(srv, test_system_svc, &sid);
229 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
230
231 rc = system_open(test_system_svc, NULL, NULL, &system);
232 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
233 PCUT_ASSERT_NOT_NULL(system);
234
235 resp.rc = EOK;
236 resp.restart_called = false;
237
238 rc = system_restart(system);
239 PCUT_ASSERT_TRUE(resp.restart_called);
240 PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
241
242 system_close(system);
243 rc = loc_service_unregister(srv, sid);
244 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
245 loc_server_unregister(srv);
246}
247
248/** 'Shutdown complete' event is delivered from server to client callback
249 * function.
250 */
251PCUT_TEST(shutdown_complete)
252{
253 errno_t rc;
254 service_id_t sid;
255 system_t *system = NULL;
256 test_response_t resp;
257 loc_srv_t *srv;
258
259 async_set_fallback_port_handler(test_system_conn, &resp);
260
261 // FIXME This causes this test to be non-reentrant!
262 rc = loc_server_register(test_system_server, &srv);
263 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
264
265 rc = loc_service_register(srv, test_system_svc, &sid);
266 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
267
268 rc = system_open(test_system_svc, &test_system_cb, &resp, &system);
269 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
270 PCUT_ASSERT_NOT_NULL(system);
271 PCUT_ASSERT_NOT_NULL(resp.srv);
272
273 resp.shutdown_complete_called = false;
274 fibril_mutex_initialize(&resp.event_lock);
275 fibril_condvar_initialize(&resp.event_cv);
276 system_srv_shutdown_complete(resp.srv);
277
278 /* Wait for the event handler to be called. */
279 fibril_mutex_lock(&resp.event_lock);
280 while (!resp.shutdown_complete_called) {
281 fibril_condvar_wait(&resp.event_cv, &resp.event_lock);
282 }
283 fibril_mutex_unlock(&resp.event_lock);
284
285 system_close(system);
286
287 rc = loc_service_unregister(srv, sid);
288 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
289 loc_server_unregister(srv);
290}
291
292/** 'Shutdown failed' event is delivered from server to client callback
293 * function.
294 */
295PCUT_TEST(shutdown_failed)
296{
297 errno_t rc;
298 service_id_t sid;
299 system_t *system = NULL;
300 test_response_t resp;
301 loc_srv_t *srv;
302
303 async_set_fallback_port_handler(test_system_conn, &resp);
304
305 // FIXME This causes this test to be non-reentrant!
306 rc = loc_server_register(test_system_server, &srv);
307 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
308
309 rc = loc_service_register(srv, test_system_svc, &sid);
310 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
311
312 rc = system_open(test_system_svc, &test_system_cb, &resp, &system);
313 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
314 PCUT_ASSERT_NOT_NULL(system);
315 PCUT_ASSERT_NOT_NULL(resp.srv);
316
317 resp.shutdown_failed_called = false;
318 fibril_mutex_initialize(&resp.event_lock);
319 fibril_condvar_initialize(&resp.event_cv);
320 system_srv_shutdown_failed(resp.srv);
321
322 /* Wait for the event handler to be called. */
323 fibril_mutex_lock(&resp.event_lock);
324 while (!resp.shutdown_failed_called) {
325 fibril_condvar_wait(&resp.event_cv, &resp.event_lock);
326 }
327 fibril_mutex_unlock(&resp.event_lock);
328
329 system_close(system);
330
331 rc = loc_service_unregister(srv, sid);
332 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
333 loc_server_unregister(srv);
334}
335
336/** Test system control service connection. */
337void test_system_conn(ipc_call_t *icall, void *arg)
338{
339 test_response_t *resp = (test_response_t *)arg;
340 system_srv_t srv;
341
342 /* Set up protocol structure */
343 system_srv_initialize(&srv);
344 srv.ops = &test_system_srv_ops;
345 srv.arg = arg;
346 resp->srv = &srv;
347
348 /* Handle connection */
349 system_conn(icall, &srv);
350
351 resp->srv = NULL;
352}
353
354/** Test system poweroff.
355 *
356 * @param arg Argument (test_response_t *)
357 */
358static errno_t test_poweroff(void *arg)
359{
360 test_response_t *resp = (test_response_t *)arg;
361
362 resp->poweroff_called = true;
363 return resp->rc;
364}
365
366/** Test system restart.
367 *
368 * @param arg Argument (test_response_t *)
369 */
370static errno_t test_restart(void *arg)
371{
372 test_response_t *resp = (test_response_t *)arg;
373
374 resp->restart_called = true;
375 return resp->rc;
376}
377
378/** Test system shutdown complete.
379 *
380 * @param arg Argument (test_response_t *)
381 */
382static void test_sys_shutdown_complete(void *arg)
383{
384 test_response_t *resp = (test_response_t *)arg;
385
386 resp->shutdown_complete_called = true;
387 fibril_condvar_signal(&resp->event_cv);
388}
389
390/** Test system shutdown failed.
391 *
392 * @param arg Argument (test_response_t *)
393 */
394static void test_sys_shutdown_failed(void *arg)
395{
396 test_response_t *resp = (test_response_t *)arg;
397
398 resp->shutdown_failed_called = true;
399}
400
401PCUT_EXPORT(system);
Note: See TracBrowser for help on using the repository browser.