~vorlon/ubuntu/raring/upstart/lp.1199778

« back to all changes in this revision

Viewing changes to init/tests/test_state.c

  • Committer: Steve Langasek
  • Date: 2013-11-07 03:06:51 UTC
  • Revision ID: steve.langasek@canonical.com-20131107030651-f1jzeyi7ifvvw1h8
Attempt to cherry-pick fixes for bug #1199778 to raring; something is still
missing though, the test suite segfaults on one of the json loads.

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
#include "log.h"
49
49
#include "blocked.h"
50
50
#include "control.h"
 
51
#include "test_util_common.h"
51
52
#include "test_util.h"
52
53
 
53
54
#ifndef TEST_DATA_DIR
147
148
        __attribute__ ((warn_unused_result));
148
149
 
149
150
void test_upstart1_6_upgrade (const char *path);
 
151
void test_session_upgrade (const char *path);
 
152
void test_session_upgrade2 (const char *original_path);
150
153
void test_upstart1_8_upgrade (const char *path);
151
154
void test_upstart_full_serialise_without_apparmor_upgrade (const char *path);
152
155
 
187
190
        { "upstart-1.6.json", test_upstart1_6_upgrade },
188
191
        { "upstart-1.8.json", test_upstart1_8_upgrade },
189
192
        { "upstart-1.8+full_serialisation-apparmor.json", test_upstart_full_serialise_without_apparmor_upgrade },
190
 
 
 
193
        { "upstart-session.json", test_session_upgrade },
 
194
        { "upstart-session2.json", test_session_upgrade2 },
191
195
        { NULL, NULL }
192
196
};
193
197
 
960
964
void
961
965
test_session_serialise (void)
962
966
{
963
 
        json_object  *json;
964
 
        json_object  *json_sessions;
965
 
        Session      *session1;
966
 
        Session      *session2;
967
 
        Session      *new_session1;
968
 
        Session      *new_session2;
969
 
        int           ret;
 
967
        json_object     *json;
 
968
        json_object     *json_sessions;
 
969
        Session         *session1;
 
970
        Session         *session2;
 
971
        Session         *new_session1;
 
972
        Session         *new_session2;
 
973
        int              ret;
 
974
        char             chroot_path[PATH_MAX];
 
975
        mode_t           old_perms;
 
976
        nih_local char  *path = NULL;
970
977
 
971
978
        session_init ();
972
979
 
973
980
        TEST_GROUP ("Session serialisation and deserialisation");
974
981
 
 
982
        /*******************************/
 
983
        TEST_FEATURE ("Session deserialisation");
 
984
 
975
985
        TEST_LIST_EMPTY (sessions);
976
986
 
977
987
        json = json_object_new_object ();
1002
1012
 
1003
1013
        TEST_LIST_EMPTY (sessions);
1004
1014
 
1005
 
        TEST_FEATURE ("Session deserialisation");
1006
 
 
1007
1015
        /* Convert the JSON back into Session objects */
1008
1016
        ret = session_deserialise_all (json);
1009
1017
        assert0 (ret);
1033
1041
        nih_free (session2);
1034
1042
        nih_free (new_session1);
1035
1043
        nih_free (new_session2);
 
1044
 
 
1045
        /*******************************/
 
1046
        TEST_FEATURE ("Ensure session deserialisation does not create JobClasses");
 
1047
 
 
1048
        clean_env ();
 
1049
 
 
1050
        TEST_LIST_EMPTY (sessions);
 
1051
        TEST_HASH_EMPTY (job_classes);
 
1052
        TEST_LIST_EMPTY (conf_sources);
 
1053
 
 
1054
        old_perms = umask (0);
 
1055
 
 
1056
        TEST_FILENAME (chroot_path);
 
1057
        assert0 (mkdir (chroot_path, 0755));
 
1058
 
 
1059
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc", chroot_path));
 
1060
        assert0 (mkdir (path, 0755));
 
1061
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc/init", chroot_path));
 
1062
        assert0 (mkdir (path, 0755));
 
1063
 
 
1064
        CREATE_FILE (path, "foo.conf", "manual");
 
1065
 
 
1066
        session1 = session_new (NULL, chroot_path);
 
1067
        TEST_NE_P (session1, NULL);
 
1068
        session1->conf_path = NIH_MUST (nih_sprintf (session1, "%s//etc/init", chroot_path));
 
1069
        TEST_LIST_NOT_EMPTY (sessions);
 
1070
 
 
1071
        TEST_HASH_EMPTY (job_classes);
 
1072
        TEST_LIST_EMPTY (conf_sources);
 
1073
 
 
1074
        json = json_object_new_object ();
 
1075
        TEST_NE_P (json, NULL);
 
1076
 
 
1077
        json_sessions = session_serialise_all ();
 
1078
        TEST_NE_P (json_sessions, NULL);
 
1079
 
 
1080
        json_object_object_add (json, "sessions", json_sessions);
 
1081
 
 
1082
        /* Remove the session from the master list (but don't free it)
 
1083
         */
 
1084
        nih_list_remove (&session1->entry);
 
1085
        TEST_LIST_EMPTY (sessions);
 
1086
 
 
1087
        clean_env ();
 
1088
 
 
1089
        /* Convert the JSON back into Session objects */
 
1090
        ret = session_deserialise_all (json);
 
1091
        assert0 (ret);
 
1092
 
 
1093
        TEST_LIST_NOT_EMPTY (sessions);
 
1094
 
 
1095
        /* Ensure no ConfSources, ConfFiles or JobClasses were created
 
1096
         * as part of the session deserialisation.
 
1097
         */
 
1098
        TEST_HASH_EMPTY (job_classes);
 
1099
        TEST_LIST_EMPTY (conf_sources);
 
1100
 
 
1101
        session2 = (Session *)nih_list_remove (sessions->next);
 
1102
        assert0 (session_diff (session1, session2));
 
1103
 
 
1104
        /* Clean up */
 
1105
 
 
1106
        /* free the JSON */
 
1107
        json_object_put (json);
 
1108
 
 
1109
        DELETE_FILE (path, "foo.conf");
 
1110
 
 
1111
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc/init", chroot_path));
 
1112
        assert0 (rmdir (path));
 
1113
 
 
1114
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc", chroot_path));
 
1115
        assert0 (rmdir (path));
 
1116
 
 
1117
        assert0 (rmdir (chroot_path));
 
1118
 
 
1119
        /* Restore */
 
1120
        umask (old_perms);
1036
1121
}
1037
1122
 
1038
1123
void
3202
3287
                                        TEST_DATA_DIR, datafile->filename));
3203
3288
 
3204
3289
                /* Ensure environment is clean before test is run */
3205
 
                TEST_LIST_EMPTY (sessions);
3206
 
                TEST_LIST_EMPTY (events);
3207
 
                TEST_LIST_EMPTY (conf_sources);
3208
 
                TEST_HASH_EMPTY (job_classes);
 
3290
                ensure_env_clean ();
3209
3291
 
3210
3292
                datafile->func (path);
3211
3293
        }
 
3294
 
 
3295
        /* Call again to make sure last test left environment sane */
 
3296
        ensure_env_clean ();
3212
3297
}
3213
3298
 
3214
3299
/**
3312
3397
}
3313
3398
 
3314
3399
/**
 
3400
 * test_session_upgrade
 
3401
 *
 
3402
 * @path: full path to JSON data file to deserialise.
 
3403
 *
 
3404
 * Test for original Upstart 1.6 serialisation data format containing
 
3405
 * a blocked object that does not contain a 'session' element.
 
3406
 *
 
3407
 * Note that this test is NOT testing whether a JobClass with an
 
3408
 * associated Upstart session is handled correctly, it is merely
 
3409
 * testing that a JobClass with the NULL session encoded in the JSON
 
3410
 * is handled correctly.
 
3411
 **/
 
3412
void
 
3413
test_session_upgrade (const char *path)
 
3414
{
 
3415
        nih_local char  *json_string = NULL;
 
3416
        struct stat      statbuf;
 
3417
        size_t           len;
 
3418
        int              got_tty1 = FALSE;
 
3419
 
 
3420
        nih_assert (path);
 
3421
 
 
3422
        conf_init ();
 
3423
        session_init ();
 
3424
        event_init ();
 
3425
        control_init ();
 
3426
        job_class_init ();
 
3427
 
 
3428
        TEST_LIST_EMPTY (sessions);
 
3429
        TEST_LIST_EMPTY (events);
 
3430
        TEST_LIST_EMPTY (conf_sources);
 
3431
        TEST_HASH_EMPTY (job_classes);
 
3432
 
 
3433
        /* Check data file exists */
 
3434
        TEST_EQ (stat (path, &statbuf), 0);
 
3435
 
 
3436
        json_string = nih_file_read (NULL, path, &len);
 
3437
        TEST_NE_P (json_string, NULL);
 
3438
 
 
3439
        /* Recreate state from JSON data file */
 
3440
        assert0 (state_from_string (json_string));
 
3441
 
 
3442
        TEST_LIST_NOT_EMPTY (conf_sources);
 
3443
        TEST_LIST_NOT_EMPTY (events);
 
3444
        TEST_HASH_NOT_EMPTY (job_classes);
 
3445
        TEST_LIST_NOT_EMPTY (sessions);
 
3446
 
 
3447
        int session_count = 0;
 
3448
        NIH_LIST_FOREACH (sessions, iter) {
 
3449
                Session *session = (Session *)iter;
 
3450
                TEST_EQ_STR (session->chroot, "/mnt");
 
3451
                TEST_EQ_STR (session->conf_path, "/mnt/etc/init");
 
3452
                session_count++;
 
3453
        }
 
3454
        TEST_EQ (session_count, 1);
 
3455
 
 
3456
        int source_types[3] = {0, 0, 0};
 
3457
 
 
3458
        NIH_LIST_FOREACH (conf_sources, iter) {
 
3459
                ConfSource *source = (ConfSource *) iter;
 
3460
                if (! source->session) {
 
3461
                        switch (source->type) {
 
3462
                        case CONF_FILE:
 
3463
                                source_types[0]++;
 
3464
                                break;
 
3465
                        case CONF_JOB_DIR:
 
3466
                                source_types[1]++;
 
3467
                                break;
 
3468
                        default:
 
3469
                                nih_assert_not_reached ();
 
3470
                        }
 
3471
                } else {
 
3472
                        switch (source->type) {
 
3473
                        case CONF_JOB_DIR:
 
3474
                                source_types[2]++;
 
3475
                                break;
 
3476
                        default:
 
3477
                                nih_assert_not_reached ();
 
3478
                        }
 
3479
                }
 
3480
        }
 
3481
        TEST_EQ (source_types[0], 1);
 
3482
        TEST_EQ (source_types[1], 1);
 
3483
        TEST_EQ (source_types[2], 1);
 
3484
 
 
3485
        NIH_HASH_FOREACH (job_classes, iter) {
 
3486
                JobClass *class = (JobClass *)iter;
 
3487
                TEST_EQ_P (class->session, NULL);
 
3488
                if (! strcmp (class->name, "tty1"))
 
3489
                        got_tty1 = TRUE;
 
3490
        }
 
3491
 
 
3492
        /* XXX: The json contains 2 tty1 jobs: one in the NULL session,
 
3493
         * and the other in the chroot session.
 
3494
         *
 
3495
         * Make sure that duplicate job names (albeit in different sessions)
 
3496
         * do not stop the NULL session job from being recreated.
 
3497
         */
 
3498
        TEST_EQ (got_tty1, TRUE);
 
3499
 
 
3500
        nih_free (conf_sources);
 
3501
        nih_free (job_classes);
 
3502
        nih_free (events);
 
3503
        nih_free (sessions);
 
3504
 
 
3505
        conf_sources = NULL;
 
3506
        job_classes = NULL;
 
3507
        events = NULL;
 
3508
        sessions = NULL;
 
3509
 
 
3510
        conf_init ();
 
3511
        job_class_init ();
 
3512
        event_init ();
 
3513
        session_init ();
 
3514
}
 
3515
 
 
3516
 
 
3517
/**
 
3518
 * test_session_upgrade2
 
3519
 *
 
3520
 * @path: full path to JSON data file that needs pre-processing.
 
3521
 *
 
3522
 * XXX: @path contains multiple occurences of @CHROOT_PATH@ which must
 
3523
 * be replaced by a valid temporary directory path before attempting
 
3524
 * deserialisation.
 
3525
 *
 
3526
 * Test to ensure Upstart can deserialise a state file containing a
 
3527
 * chroot session where that chroot path actually exists with jobs on disk.
 
3528
 * This was added since that exact scenario caught a bug in an early fix
 
3529
 * for LP:#1199778 (resulting in stateless re-exec).
 
3530
 **/
 
3531
void
 
3532
test_session_upgrade2 (const char *original_path)
 
3533
{
 
3534
        nih_local char  *json_string = NULL;
 
3535
        struct stat      statbuf;
 
3536
        size_t           len;
 
3537
        int              got_tty1 = FALSE;
 
3538
        char             chroot_path[PATH_MAX];
 
3539
        nih_local char  *path = NULL;
 
3540
        nih_local char  *file = NULL;
 
3541
        nih_local char  *processed_json = NULL;
 
3542
        mode_t           old_perms;
 
3543
 
 
3544
        nih_assert (original_path);
 
3545
 
 
3546
        conf_init ();
 
3547
        session_init ();
 
3548
        event_init ();
 
3549
        control_init ();
 
3550
        job_class_init ();
 
3551
 
 
3552
        TEST_LIST_EMPTY (sessions);
 
3553
        TEST_LIST_EMPTY (events);
 
3554
        TEST_LIST_EMPTY (conf_sources);
 
3555
        TEST_HASH_EMPTY (job_classes);
 
3556
 
 
3557
        /* Check data file exists */
 
3558
        TEST_EQ (stat (original_path, &statbuf), 0);
 
3559
 
 
3560
        /* Read the original file */
 
3561
        file = nih_file_read (NULL, original_path, &len);
 
3562
        TEST_NE_P (file, NULL);
 
3563
 
 
3564
        old_perms = umask (0);
 
3565
 
 
3566
        TEST_FILENAME (chroot_path);
 
3567
        assert0 (mkdir (chroot_path, 0755));
 
3568
 
 
3569
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc", chroot_path));
 
3570
        assert0 (mkdir (path, 0755));
 
3571
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc/init", chroot_path));
 
3572
        assert0 (mkdir (path, 0755));
 
3573
 
 
3574
        /* Replace @CHROOT_PATH@ with our temporary path */
 
3575
        processed_json = search_and_replace (NULL, file, "@CHROOT_PATH@", chroot_path);
 
3576
        TEST_NE_P (processed_json, NULL);
 
3577
 
 
3578
        /* Create some jobs which are also specified in the original
 
3579
         * JSON state data.
 
3580
         */
 
3581
        CREATE_FILE (path, "tty1.conf", "manual");
 
3582
        CREATE_FILE (path, "tty2.conf", "manual");
 
3583
 
 
3584
        /* Recreate state from JSON data file */
 
3585
        assert0 (state_from_string (processed_json));
 
3586
 
 
3587
        TEST_LIST_NOT_EMPTY (conf_sources);
 
3588
        TEST_LIST_NOT_EMPTY (events);
 
3589
        TEST_HASH_NOT_EMPTY (job_classes);
 
3590
        TEST_LIST_NOT_EMPTY (sessions);
 
3591
 
 
3592
        int session_count = 0;
 
3593
        NIH_LIST_FOREACH (sessions, iter) {
 
3594
                Session *session = (Session *)iter;
 
3595
                nih_local char *new_path = NULL;
 
3596
 
 
3597
                /* yes, there is a double-slash in this path */
 
3598
                new_path = nih_sprintf (NULL, "%s/%s", chroot_path,
 
3599
                                "/etc/init");
 
3600
 
 
3601
                TEST_EQ_STR (session->chroot, chroot_path);
 
3602
                TEST_EQ_STR (session->conf_path, new_path);
 
3603
                session_count++;
 
3604
        }
 
3605
        TEST_EQ (session_count, 1);
 
3606
 
 
3607
        int source_types[3] = {0, 0, 0};
 
3608
 
 
3609
        NIH_LIST_FOREACH (conf_sources, iter) {
 
3610
                ConfSource *source = (ConfSource *) iter;
 
3611
 
 
3612
                if (! source->session) {
 
3613
                        switch (source->type) {
 
3614
                        case CONF_FILE:
 
3615
                                source_types[0]++;
 
3616
                                break;
 
3617
                        case CONF_JOB_DIR:
 
3618
                                source_types[1]++;
 
3619
                                break;
 
3620
                        default:
 
3621
                                nih_assert_not_reached ();
 
3622
                        }
 
3623
                } else {
 
3624
                        switch (source->type) {
 
3625
                        case CONF_JOB_DIR:
 
3626
                                source_types[2]++;
 
3627
                                break;
 
3628
                        default:
 
3629
                                nih_assert_not_reached ();
 
3630
                        }
 
3631
                }
 
3632
        }
 
3633
        TEST_EQ (source_types[0], 1);
 
3634
        TEST_EQ (source_types[1], 1);
 
3635
        TEST_EQ (source_types[2], 1);
 
3636
 
 
3637
        NIH_HASH_FOREACH (job_classes, iter) {
 
3638
                JobClass *class = (JobClass *)iter;
 
3639
 
 
3640
                TEST_EQ_P (class->session, NULL);
 
3641
                if (! strcmp (class->name, "tty1"))
 
3642
                        got_tty1 = TRUE;
 
3643
        }
 
3644
 
 
3645
        /* XXX: The json contains 2 tty1 jobs: one in the NULL session,
 
3646
         * and the other in the chroot session.
 
3647
         *
 
3648
         * Make sure that duplicate job names (albeit in different sessions)
 
3649
         * do not stop the NULL session job from being recreated.
 
3650
         */
 
3651
        TEST_EQ (got_tty1, TRUE);
 
3652
 
 
3653
        nih_free (conf_sources);
 
3654
        nih_free (job_classes);
 
3655
        nih_free (events);
 
3656
        nih_free (sessions);
 
3657
 
 
3658
        conf_sources = NULL;
 
3659
        job_classes = NULL;
 
3660
        events = NULL;
 
3661
        sessions = NULL;
 
3662
 
 
3663
        conf_init ();
 
3664
        job_class_init ();
 
3665
        event_init ();
 
3666
        session_init ();
 
3667
 
 
3668
        DELETE_FILE (path, "tty1.conf");
 
3669
        DELETE_FILE (path, "tty2.conf");
 
3670
 
 
3671
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc/init", chroot_path));
 
3672
        assert0 (rmdir (path));
 
3673
 
 
3674
        path = NIH_MUST (nih_sprintf (NULL, "%s/etc", chroot_path));
 
3675
        assert0 (rmdir (path));
 
3676
 
 
3677
        assert0 (rmdir (chroot_path));
 
3678
 
 
3679
        /* Restore */
 
3680
        umask (old_perms);
 
3681
}
 
3682
 
 
3683
/**
3315
3684
 * test_upstart1_8_upgrade:
3316
3685
 *
3317
3686
 * @path: full path to JSON data file to deserialise.
3520
3889
}
3521
3890
 
3522
3891
 
 
3892
 
 
3893
/**
 
3894
 * conf_source_from_path:
 
3895
 *
 
3896
 * @path: path to consider,
 
3897
 * @type: tyoe of ConfSource to check for,
 
3898
 * @session: session.
 
3899
 *
 
3900
 * Look for a ConfSource with path @path, type @type and session
 
3901
 * @session.
 
3902
 *
 
3903
 * Returns: Matching ConfSource or NULL if not found.
 
3904
 */
 
3905
ConfSource *
 
3906
conf_source_from_path (const char *path, ConfSourceType type, const Session *session)
 
3907
{
 
3908
        nih_assert (path);
 
3909
 
 
3910
        NIH_LIST_FOREACH (conf_sources, iter) {
 
3911
                ConfSource *source = (ConfSource *)iter;
 
3912
                if (! strcmp (source->path, path)
 
3913
                                && source->type == type && source->session == session)
 
3914
                        return source;
 
3915
        }
 
3916
 
 
3917
        return NULL;
 
3918
}
 
3919
 
3523
3920
int
3524
3921
main (int   argc,
3525
3922
      char *argv[])
3548
3945
 
3549
3946
        return 0;
3550
3947
}
3551
 
 
3552
 
/**
3553
 
 * conf_source_from_path:
3554
 
 *
3555
 
 * @path: path to consider,
3556
 
 * @type: tyoe of ConfSource to check for,
3557
 
 * @session: session.
3558
 
 *
3559
 
 * Look for a ConfSource with path @path, type @type and session
3560
 
 * @session.
3561
 
 *
3562
 
 * Returns: Matching ConfSource or NULL if not found.
3563
 
 */
3564
 
ConfSource *
3565
 
conf_source_from_path (const char *path, ConfSourceType type, const Session *session)
3566
 
{
3567
 
        nih_assert (path);
3568
 
 
3569
 
        NIH_LIST_FOREACH (conf_sources, iter) {
3570
 
                ConfSource *source = (ConfSource *)iter;
3571
 
                if (! strcmp (source->path, path)
3572
 
                                && source->type == type && source->session == session)
3573
 
                        return source;
3574
 
        }
3575
 
 
3576
 
        return NULL;
3577
 
}