ac918947cd1d87d32553abfc83302c30dbc80df9
[platform/upstream/connman.git] / tools / session-test.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2011  BWM CarIT GmbH. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <pwd.h>
29 #include <sys/types.h>
30
31 #include <gdbus.h>
32
33 #include "session-test.h"
34
35 #define POLICYDIR STORAGEDIR "/session_policy_local"
36
37 enum test_session_state {
38         TEST_SESSION_STATE_0 = 0,
39         TEST_SESSION_STATE_1 = 1,
40         TEST_SESSION_STATE_2 = 2,
41         TEST_SESSION_STATE_3 = 3,
42 };
43
44 static enum test_session_state get_session_state(struct test_session *session)
45 {
46         return GPOINTER_TO_UINT(session->fix->user_data);
47 }
48
49 static void set_session_state(struct test_session *session,
50                                 enum test_session_state state)
51 {
52         session->fix->user_data = GUINT_TO_POINTER(state);
53 }
54
55 static struct test_session *get_session(struct test_session *session,
56                                         unsigned int index)
57 {
58         return &session->fix->session[index];
59 }
60
61 static gboolean test_session_create_no_notify(gpointer data)
62 {
63         struct test_fix *fix = data;
64         DBusMessage *msg;
65
66         util_session_create(fix, 1);
67
68         msg = manager_create_session(fix->session->connection,
69                                         fix->session->info, "/foo");
70         g_assert(msg != NULL);
71         g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR);
72
73         dbus_message_unref(msg);
74
75         util_idle_call(fix, util_quit_loop, util_session_destroy);
76
77         return FALSE;
78 }
79
80 static gboolean test_session_destroy_no_notify(gpointer data)
81 {
82         struct test_fix *fix = data;
83         DBusMessage *msg;
84
85         util_session_create(fix, 1);
86
87         msg = manager_destroy_session(fix->session->connection, "/foo");
88         g_assert(msg == NULL);
89
90         util_idle_call(fix, util_quit_loop, util_session_destroy);
91
92         return FALSE;
93 }
94
95 static void test_session_create_notify(struct test_session *session)
96 {
97         LOG("session %p", session);
98
99         util_idle_call(session->fix, util_quit_loop, util_session_destroy);
100 }
101
102 static gboolean test_session_create(gpointer data)
103 {
104         struct test_fix *fix = data;
105         struct test_session *session;
106         DBusMessage *msg;
107         int err;
108
109         util_session_create(fix, 1);
110         session = fix->session;
111
112         session->notify_path = "/foo";
113         session->notify = test_session_create_notify;
114
115         err = session_notify_register(session, session->notify_path);
116         g_assert(err == 0);
117
118         msg = manager_create_session(session->connection,
119                                         session->info,
120                                         session->notify_path);
121         g_assert(msg != NULL);
122         g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR);
123
124         dbus_message_unref(msg);
125
126         return FALSE;
127 }
128
129 static gboolean test_session_create_destroy(gpointer data)
130 {
131         struct test_fix *fix = data;
132         struct test_session *session;
133
134         util_session_create(fix, 1);
135         session = fix->session;
136
137         session->notify_path = g_strdup("/foo");
138
139         util_session_init(fix->session);
140         util_session_cleanup(fix->session);
141
142         util_idle_call(fix, util_quit_loop, util_session_destroy);
143
144         return FALSE;
145 }
146
147 static gboolean test_session_create_already_exists(gpointer data)
148 {
149         struct test_fix *fix = data;
150         struct test_session *session0, *session1;
151         DBusMessage *msg;
152
153         util_session_create(fix, 2);
154         session0 = &fix->session[0];
155         session1 = &fix->session[1];
156
157         session0->notify_path = g_strdup("/foo");
158         session1->notify_path = session0->notify_path;
159
160         util_session_init(session0);
161
162         msg = manager_create_session(session1->connection,
163                                         session1->info,
164                                         session1->notify_path);
165         g_assert(msg == NULL);
166
167         util_session_cleanup(session0);
168
169         util_idle_call(fix, util_quit_loop, util_session_destroy);
170
171         return FALSE;
172 }
173
174 static void test_session_create_many_notify(struct test_session *session)
175 {
176         unsigned int nr;
177
178         LOG("session %p", session);
179
180         nr = GPOINTER_TO_UINT(session->fix->user_data);
181         nr--;
182         session->fix->user_data = GUINT_TO_POINTER(nr);
183
184         if (nr > 0)
185                 return;
186
187         util_idle_call(session->fix, util_quit_loop, util_session_destroy);
188 }
189
190 static gboolean test_session_create_many(gpointer data)
191 {
192         struct test_fix *fix = data;
193         struct test_session *session;
194         unsigned int i, max;
195
196         max = 100;
197
198         fix->user_data = GUINT_TO_POINTER(max);
199
200         util_session_create(fix, max);
201
202         for (i = 0; i < max; i++) {
203                 session = &fix->session[i];
204
205                 session->notify_path = g_strdup_printf("/foo/%d", i);
206                 session->notify = test_session_create_many_notify;
207
208                 util_session_init(session);
209         }
210
211         return FALSE;
212 }
213
214 static void set_session_mode(struct test_fix *fix,
215                                         connman_bool_t enable)
216 {
217         DBusMessage *msg;
218
219         msg = manager_set_session_mode(fix->main_connection, enable);
220         g_assert(msg != NULL);
221         g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR);
222
223         dbus_message_unref(msg);
224 }
225
226 static void test_session_connect_notify(struct test_session *session)
227 {
228         LOG("session %p state %d", session, session->info->state);
229
230         if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
231                 return;
232
233         util_session_cleanup(session);
234
235         util_idle_call(session->fix, util_quit_loop, util_session_destroy);
236 }
237
238 static gboolean test_session_connect(gpointer data)
239 {
240         struct test_fix *fix = data;
241         struct test_session *session;
242         DBusMessage *msg;
243
244         util_session_create(fix, 1);
245         session = fix->session;
246
247         session->notify_path = g_strdup("/foo");
248         session->notify =  test_session_connect_notify;
249         util_session_init(session);
250
251         msg = session_connect(session->connection, session);
252         g_assert(msg != NULL);
253         g_assert(dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR);
254
255         dbus_message_unref(msg);
256
257         return FALSE;
258 }
259
260 static void test_session_disconnect_notify(struct test_session *session)
261 {
262         LOG("session %p state %d", session, session->info->state);
263
264         if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED)
265                 return;
266
267         util_session_cleanup(session);
268
269         util_idle_call(session->fix, util_quit_loop, util_session_destroy);
270 }
271
272 static gboolean test_session_disconnect(gpointer data)
273 {
274         struct test_fix *fix = data;
275         struct test_session *session;
276         DBusMessage *msg;
277
278         util_session_create(fix, 1);
279         session = fix->session;
280
281         session->notify_path = g_strdup("/foo");
282         session->notify =  test_session_disconnect_notify;
283         util_session_init(session);
284
285         msg = session_disconnect(session->connection, session);
286         g_assert(msg != NULL);
287         dbus_message_unref(msg);
288
289         return FALSE;
290 }
291
292 static void test_session_connect_disconnect_notify(struct test_session *session)
293 {
294         enum test_session_state state = get_session_state(session);
295         enum test_session_state next_state = state;
296         DBusMessage *msg;
297
298         LOG("state %d session %p %s state %d", state, session,
299                 session->notify_path, session->info->state);
300
301         switch (state) {
302         case TEST_SESSION_STATE_0:
303                 if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
304                         next_state = TEST_SESSION_STATE_1;
305                 break;
306         case TEST_SESSION_STATE_1:
307                 if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED)
308                         next_state = TEST_SESSION_STATE_2;
309                 break;
310         case TEST_SESSION_STATE_2:
311                 if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
312                         next_state = TEST_SESSION_STATE_3;
313         default:
314                 break;
315         }
316
317         if (state == next_state)
318                 return;
319
320         set_session_state(session, next_state);
321
322         LOG("next_state %d", next_state);
323
324         switch (next_state) {
325         case TEST_SESSION_STATE_1:
326                 msg = session_connect(session->connection, session);
327                 g_assert(msg != NULL);
328                 dbus_message_unref(msg);
329                 return;
330         case TEST_SESSION_STATE_2:
331                 msg = session_disconnect(session->connection, session);
332                 g_assert(msg != NULL);
333                 dbus_message_unref(msg);
334                 return;
335         case TEST_SESSION_STATE_3:
336                 util_session_cleanup(session);
337                 util_idle_call(session->fix, util_quit_loop,
338                                 util_session_destroy);
339                 return;
340         default:
341                 return;
342         }
343 }
344
345 static gboolean test_session_connect_disconnect(gpointer data)
346 {
347         struct test_fix *fix = data;
348         struct test_session *session;
349
350         /*
351          * +-------------------+
352          * |       START       |
353          * +-------------------+
354          *   |
355          *   | connect foo
356          *   v
357          * +-------------------+
358          * |   FOO-CONNECTED   |
359          * +-------------------+
360          *  |
361          *  | disconnect foo
362          *  v
363          * +-------------------+
364          * |        END        |
365          * +-------------------+
366          */
367
368         util_session_create(fix, 1);
369         session = fix->session;
370
371         session->notify_path = g_strdup("/foo");
372         session->notify =  test_session_connect_disconnect_notify;
373
374         util_session_init(session);
375
376         set_session_state(session, TEST_SESSION_STATE_0);
377
378         return FALSE;
379 }
380
381 static void test_session_connect_free_ride_notify(struct test_session *session)
382 {
383         struct test_session *session0 = get_session(session, 0);
384         struct test_session *session1 = get_session(session, 1);
385         enum test_session_state state = get_session_state(session);
386         enum test_session_state next_state = state;
387         DBusMessage *msg;
388
389         LOG("state %d session %p %s state %d", state, session,
390                 session->notify_path, session->info->state);
391
392         switch (state) {
393         case TEST_SESSION_STATE_0:
394                 if (session0->info->state == CONNMAN_SESSION_STATE_DISCONNECTED
395                                 && session1->info->state ==
396                                         CONNMAN_SESSION_STATE_DISCONNECTED) {
397                         next_state = TEST_SESSION_STATE_1;
398                 }
399
400                 break;
401         case TEST_SESSION_STATE_1:
402                 if (session0->info->state >= CONNMAN_SESSION_STATE_CONNECTED &&
403                                 session1->info->state >=
404                                         CONNMAN_SESSION_STATE_CONNECTED) {
405                         next_state = TEST_SESSION_STATE_2;
406                 }
407
408                 break;
409         case TEST_SESSION_STATE_2:
410                 if (session0->info->state == CONNMAN_SESSION_STATE_DISCONNECTED
411                                 && session1->info->state ==
412                                         CONNMAN_SESSION_STATE_DISCONNECTED) {
413                         next_state = TEST_SESSION_STATE_3;
414                 }
415
416                 break;
417         case TEST_SESSION_STATE_3:
418
419                 return;
420         }
421
422         if (state == next_state)
423                 return;
424
425         set_session_state(session, next_state);
426
427         LOG("next_state %d", next_state);
428
429         switch (next_state) {
430         case TEST_SESSION_STATE_0:
431
432                 return;
433         case TEST_SESSION_STATE_1:
434                 msg = session_connect(session0->connection, session0);
435                 g_assert(msg != NULL);
436                 dbus_message_unref(msg);
437
438                 return;
439
440         case TEST_SESSION_STATE_2:
441                 msg = session_disconnect(session0->connection, session0);
442                 g_assert(msg != NULL);
443                 dbus_message_unref(msg);
444
445                 return;
446         case TEST_SESSION_STATE_3:
447                 util_session_cleanup(session0);
448                 util_session_cleanup(session1);
449
450                 util_idle_call(session0->fix, util_quit_loop,
451                                 util_session_destroy);
452
453                 return;
454         }
455 }
456
457 static gboolean test_session_connect_free_ride(gpointer data)
458 {
459         struct test_fix *fix = data;
460         struct test_session *session0, *session1;
461
462         /*
463          * +-------------------+
464          * |       START       |
465          * +-------------------+
466          *   |
467          *   | connect foo
468          *   v
469          * +-------------------+
470          * |   FOO-CONNECTED   |
471          * +-------------------+
472          *   |
473          *   | free-ride bar
474          *   v
475          * +-------------------+
476          * | FOO-BAR-CONNECTED |
477          * +-------------------+
478          *  |
479          *  | disconnect foo
480          *  v
481          * +-------------------+
482          * |        END        |
483          * +-------------------+
484          */
485
486         util_session_create(fix, 2);
487         session0 = &fix->session[0];
488         session1 = &fix->session[1];
489
490         session0->notify_path = g_strdup("/foo");
491         session1->notify_path = g_strdup("/bar");
492         session0->notify = test_session_connect_free_ride_notify;
493         session1->notify = test_session_connect_free_ride_notify;
494
495         util_session_init(session0);
496         util_session_init(session1);
497
498         set_session_state(session0, TEST_SESSION_STATE_0);
499
500         return FALSE;
501 }
502
503 static void policy_save(GKeyFile *keyfile, char *pathname)
504 {
505         gchar *data = NULL;
506         gsize length = 0;
507         GError *error = NULL;
508
509         data = g_key_file_to_data(keyfile, &length, NULL);
510
511         if(!g_file_set_contents(pathname, data, length, &error)) {
512                 DBG("Failed to store information: %s", error->message);
513                 g_error_free(error);
514                 g_assert(0);
515         }
516
517         g_free(data);
518 }
519
520 static void policy_allowed_bearers(const char *allowed_bearers)
521 {
522         struct passwd *pwd;
523         uid_t uid;
524         char *pathname;
525         GKeyFile *keyfile;
526
527         LOG("update to '%s'", allowed_bearers);
528
529         uid = getuid();
530         pwd = getpwuid(uid);
531         g_assert(pwd != NULL);
532
533         keyfile = g_key_file_new();
534         g_key_file_set_string(keyfile, "policy_foo", "uid", pwd->pw_name);
535         g_key_file_set_string(keyfile, "policy_foo", "AllowedBearers",
536                                 allowed_bearers);
537
538         pathname = g_strdup_printf("%s/foo.policy", POLICYDIR);
539         policy_save(keyfile, pathname);
540
541         g_free(pathname);
542         g_key_file_free(keyfile);
543 }
544
545 static void policy_remove_file(void)
546 {
547         char *pathname;
548
549         pathname = g_strdup_printf("%s/foo.policy", POLICYDIR);
550         unlink(pathname);
551         g_free(pathname);
552 }
553
554 static void test_session_policy_notify(struct test_session *session)
555 {
556         enum test_session_state state = get_session_state(session);
557         enum test_session_state next_state = state;
558         DBusMessage *msg;
559
560         LOG("state %d session %p %s state %d", state, session,
561                 session->notify_path, session->info->state);
562
563         switch (state) {
564         case TEST_SESSION_STATE_0:
565                 if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
566                         next_state = TEST_SESSION_STATE_1;
567                 break;
568         case TEST_SESSION_STATE_1:
569                 if (session->info->state >= CONNMAN_SESSION_STATE_CONNECTED)
570                         next_state = TEST_SESSION_STATE_2;
571                 break;
572         case TEST_SESSION_STATE_2:
573                 if (session->info->state == CONNMAN_SESSION_STATE_DISCONNECTED)
574                         next_state = TEST_SESSION_STATE_3;
575         default:
576                 break;
577         }
578
579         if (state == next_state)
580                 return;
581
582         set_session_state(session, next_state);
583
584         LOG("next_state %d", next_state);
585
586         switch (next_state) {
587         case TEST_SESSION_STATE_1:
588                 policy_allowed_bearers("ethernet");
589
590                 msg = session_connect(session->connection, session);
591                 g_assert(msg != NULL);
592                 dbus_message_unref(msg);
593                 return;
594         case TEST_SESSION_STATE_2:
595                 policy_allowed_bearers("");
596                 return;
597         case TEST_SESSION_STATE_3:
598                 policy_remove_file();
599                 util_session_cleanup(session);
600                 util_idle_call(session->fix, util_quit_loop,
601                                 util_session_destroy);
602                 return;
603         default:
604                 return;
605         }
606 }
607
608 static gboolean test_session_policy(gpointer data)
609 {
610         struct test_fix *fix = data;
611         struct test_session *session;
612
613         /*
614          * +-------------------+
615          * |       START       |
616          * +-------------------+
617          *   |
618          *   | write policy AllowedBearers = ethernet
619          *   v
620          * +-------------------+
621          * |   FOO-CONNECTED   |
622          * +-------------------+
623          *  |
624          *  | write policy AllowedBearers =
625          *  v
626          * +-------------------+
627          * |        END        |
628          * +-------------------+
629          */
630
631         policy_remove_file();
632
633         util_session_create(fix, 1);
634         session = fix->session;
635
636         session->notify_path = g_strdup("/foo");
637         session->notify =  test_session_policy_notify;
638
639         util_session_init(session);
640
641         set_session_state(session, TEST_SESSION_STATE_0);
642
643         return FALSE;
644 }
645
646 static connman_bool_t is_online(struct test_fix *fix)
647 {
648         if (g_strcmp0(fix->manager.state, "online") == 0)
649                 return TRUE;
650
651         return FALSE;
652 }
653
654 static gboolean enable_session_mode(gpointer data)
655 {
656         struct test_fix *fix = data;
657
658         set_session_mode(fix, TRUE);
659
660         if (is_online(fix) == FALSE)
661                 util_idle_call(fix, util_quit_loop, NULL);
662
663         return FALSE;
664 }
665
666 static gboolean manager_state_changed(gpointer data)
667 {
668         struct test_fix *fix = data;
669
670         if (is_online(fix) == FALSE) {
671                 fix->manager_changed = NULL;
672                 util_idle_call(fix, util_quit_loop, NULL);
673         }
674
675         return FALSE;
676 }
677
678 static gboolean disable_session_mode(gpointer data)
679 {
680         struct test_fix *fix = data;
681
682         set_session_mode(fix, FALSE);
683
684         return FALSE;
685 }
686
687 static void setup_cb(struct test_fix *fix, gconstpointer data)
688 {
689         fix->manager_changed = manager_state_changed;
690
691         util_setup(fix, data);
692         util_call(fix, enable_session_mode, NULL);
693
694         g_main_loop_run(fix->main_loop);
695
696         fix->manager_changed = NULL;
697 }
698
699 static void teardown_cb(struct test_fix *fix, gconstpointer data)
700 {
701         util_call(fix, disable_session_mode, NULL);
702         util_idle_call(fix, util_quit_loop, NULL);
703
704         g_main_loop_run(fix->main_loop);
705
706         util_teardown(fix, data);
707 }
708
709 int main(int argc, char *argv[])
710 {
711         g_test_init(&argc, &argv, NULL);
712
713         util_test_add("/manager/session create no notify",
714                 test_session_create_no_notify, setup_cb, teardown_cb);
715         util_test_add("/manager/session destroy no notify",
716                 test_session_destroy_no_notify, setup_cb, teardown_cb);
717         util_test_add("/manager/session create",
718                 test_session_create, setup_cb, teardown_cb);
719         util_test_add("/manager/session create destroy",
720                 test_session_create_destroy, setup_cb, teardown_cb);
721         util_test_add("/manager/session create already exists",
722                 test_session_create_already_exists, setup_cb, teardown_cb);
723         util_test_add("/manager/session create many",
724                 test_session_create_many, setup_cb, teardown_cb);
725
726         util_test_add("/session/connect",
727                 test_session_connect, setup_cb, teardown_cb);
728         util_test_add("/session/disconnect",
729                 test_session_disconnect, setup_cb, teardown_cb);
730         util_test_add("/session/connect disconnect",
731                 test_session_connect_disconnect, setup_cb, teardown_cb);
732         util_test_add("/session/connect free-ride",
733                 test_session_connect_free_ride, setup_cb, teardown_cb);
734
735         util_test_add("/session/policy",
736                 test_session_policy, setup_cb, teardown_cb);
737
738         return g_test_run();
739 }