~cweber10/ubuntu/precise/upstart/lp.793554

« back to all changes in this revision

Viewing changes to util/tests/test_user_sessions.sh

  • Committer: James Hunt
  • Date: 2012-01-26 15:14:49 UTC
  • Revision ID: james.hunt@ubuntu.com-20120126151449-h1phjaf4h5fro2h9
Merge of important logger fixes from upstream lp:upstart
(LP: #912558).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/sh
 
2
#---------------------------------------------------------------------
 
3
# Script to run minimal Upstart user session tests.
 
4
#
 
5
# Note that this script _cannot_ be run as part of the "make check"
 
6
# tests since those tests stimulate functions and features of the
 
7
# as-yet-uninstalled version of Upstart. However, this script needs to
 
8
# run on a system where the version of Upstart under test has _already_
 
9
# been fully installed.
 
10
#---------------------------------------------------------------------
 
11
#
 
12
# Copyright (C) 2011 Canonical Ltd.
 
13
#
 
14
# Author: James Hunt <james.hunt@canonical.com>
 
15
#
 
16
# This program is free software: you can redistribute it and/or modify
 
17
# it under the terms of the GNU General Public License as published by
 
18
# the Free Software Foundation, version 3 of the License.
 
19
#
 
20
# This program is distributed in the hope that it will be useful,
 
21
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
# GNU General Public License for more details.
 
24
#
 
25
# You should have received a copy of the GNU General Public License
 
26
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
27
#
 
28
#---------------------------------------------------------------------
 
29
 
 
30
script_name=${0##*/}
 
31
sys_job_dir="/etc/init"
 
32
user_job_dir="$HOME/.init"
 
33
user_log_dir="$HOME/.cache/upstart/log"
 
34
sys_log_dir="/var/log/upstart"
 
35
bug_url="https://bugs.launchpad.net/upstart/+filebug"
 
36
test_dir=
 
37
test_dir_suffix=
 
38
user_to_create=
 
39
uid=
 
40
gid=
 
41
opt=
 
42
OPTARG=
 
43
debug_enabled=0
 
44
feature=
 
45
 
 
46
# allow non-priv users to find 'initctl'
 
47
export PATH=$PATH:/sbin
 
48
 
 
49
# for assertions
 
50
die()
 
51
{
 
52
  msg="$*"
 
53
  echo "ERROR: $msg" >&2
 
54
  exit 1
 
55
}
 
56
 
 
57
debug()
 
58
{
 
59
  str="$1"
 
60
  [ "$debug_enabled" = 1 ] && echo "DEBUG: $str"
 
61
}
 
62
 
 
63
get_job_pid()
 
64
{
 
65
  job="$1"
 
66
  [ -z "$job" ] && die "need job"
 
67
 
 
68
  pid=$(initctl status "$job"|grep process|awk '{print $NF}')
 
69
  [ -z "$pid" ] && die "job $job has no pid"
 
70
 
 
71
  echo "$pid"
 
72
}
 
73
 
 
74
# take a string and convert it into a valid job name
 
75
make_job_name()
 
76
{
 
77
  str="$1"
 
78
 
 
79
  echo "$str" |\
 
80
    sed -e 's/>/ gt /g' -e 's/</ lt /g' -e 's/+/ and /g' |\
 
81
    sed -e 's/[[:punct:]]//g' -e 's/  */ /g' |\
 
82
    tr ' ' '-'
 
83
}
 
84
 
 
85
upstart_encode()
 
86
{
 
87
  str="$1"
 
88
 
 
89
  echo "$str" | sed 's!/!_!g'
 
90
}
 
91
 
 
92
# take a string and convert it into a valid job log file name
 
93
make_log_name()
 
94
{
 
95
  str="$1"
 
96
  upstart_encode "$str"
 
97
}
 
98
 
 
99
TEST_FAILED()
 
100
{
 
101
  args="$*"
 
102
 
 
103
  [ -z "$args" ] && die "need args"
 
104
 
 
105
  echo
 
106
  echo "ERROR: TEST FAILED ('$feature')"
 
107
  echo
 
108
  printf "BAD: ${args}\n"
 
109
  printf "\nPlease report a bug at $bug_url including the following details:\n"
 
110
  printf "\nUpstart:\n"
 
111
  /sbin/init --version|head -n1
 
112
  /sbin/initctl --version|head -n1
 
113
  echo
 
114
  printf "cmdline:\n"
 
115
  cat /proc/cmdline
 
116
  echo
 
117
  printf "Upstart Env:\n"
 
118
  set|grep UPSTART_
 
119
  echo
 
120
  printf "lsb:\n"
 
121
  lsb_release -a
 
122
  printf "\nuname:\n"
 
123
  uname -a
 
124
  echo
 
125
  sync
 
126
  echo "ERROR: TEST FAILED ('$feature')"
 
127
  echo
 
128
  exit 1
 
129
}
 
130
 
 
131
TEST_GROUP()
 
132
{
 
133
  name="$1"
 
134
 
 
135
  [ -z "$name" ] && die "need name"
 
136
 
 
137
  printf "Testing %s\n" "$name"
 
138
}
 
139
 
 
140
TEST_FEATURE()
 
141
{
 
142
  feature="$1"
 
143
 
 
144
  [ -z "$feature" ] && die "need feature"
 
145
 
 
146
  printf "...%s\n" "$feature"
 
147
}
 
148
 
 
149
TEST_NE()
 
150
{
 
151
  cmd="$1"
 
152
  value="$2"
 
153
  expected="$3"
 
154
 
 
155
  # XXX: no checks on value or expected since they might be blank
 
156
  [ -z "$cmd" ] && die "need cmd"
 
157
 
 
158
  [ "$value" = "$expected" ] && TEST_FAILED \
 
159
  "wrong value for '$cmd', expected $expected got $value"
 
160
}
 
161
 
 
162
TEST_EQ()
 
163
{
 
164
  cmd="$1"
 
165
  value="$2"
 
166
  expected="$3"
 
167
 
 
168
  # XXX: no checks on value or expected since they might be blank
 
169
  [ -z "$cmd" ] && die "need cmd"
 
170
 
 
171
  [ "$value" != "$expected" ] && TEST_FAILED \
 
172
  "wrong value for '$cmd', expected '$expected' got '$value'"
 
173
}
 
174
 
 
175
checks()
 
176
{
 
177
  cmd=initctl
 
178
  [ -z "$(command -v $cmd)" ] && die "cannot find command $cmd"
 
179
 
 
180
  [ "$(id -u)" = 0 ] && die "ERROR: should not run this function as root"
 
181
 
 
182
  # This will fail for a non-root user unless D-Bus is correctly
 
183
  # configured
 
184
  $cmd emit foo || die \
 
185
    "You do not appear to have configured D-Bus for Upstart user sessions. See usage."
 
186
}
 
187
 
 
188
setup()
 
189
{
 
190
  uid=$(id -u)
 
191
  gid=$(id -g)
 
192
 
 
193
  if [ "$uid" = 0 ]
 
194
  then
 
195
    [ -z "$user_to_create" ] && die "need '-u' option when running as root"
 
196
 
 
197
    getent passwd "$user_to_create" && \
 
198
      die "user '$user_to_create' already exists"
 
199
 
 
200
    echo "Creating user '$user_to_create'"
 
201
    cmd="useradd -mU -c 'Upstart Test User' $user_to_create"
 
202
    eval "$cmd"
 
203
    TEST_EQ "$cmd" $? 0
 
204
 
 
205
    echo "Locking account for user '$user_to_create'"
 
206
    cmd="usermod -L $user_to_create"
 
207
    eval "$cmd"
 
208
    TEST_EQ "$cmd" $? 0
 
209
 
 
210
    # Run ourselves again as the new user
 
211
    su -c "$0 -a" "$user_to_create"
 
212
    test_run_rc=$?
 
213
 
 
214
    if [ $test_run_rc -eq 0 ]
 
215
    then
 
216
      echo "Deleting user '$user_to_create'"
 
217
      cmd="userdel -r \"$user_to_create\""
 
218
      eval "$cmd"
 
219
      TEST_EQ "$cmd" $? 0
 
220
    fi
 
221
 
 
222
    exit $test_run_rc
 
223
  fi
 
224
 
 
225
  checks
 
226
 
 
227
  # setup
 
228
  if [ ! -d "$user_job_dir" ]
 
229
  then
 
230
    cmd="mkdir -p \"$user_job_dir\""
 
231
    eval $cmd
 
232
    TEST_EQ "$cmd" $? 0
 
233
 
 
234
    cmd="chmod 755 \"$user_job_dir\""
 
235
    eval "$cmd"
 
236
    TEST_EQ "$cmd" $? 0
 
237
  fi
 
238
 
 
239
  # create somewhere to store user jobs
 
240
  cmd="mktemp -d --tmpdir=\"$user_job_dir\""
 
241
  test_dir=$(eval "$cmd")
 
242
  TEST_EQ "$cmd" $? 0
 
243
  TEST_NE "$test_dir" "$test_dir" ""
 
244
  test_dir_suffix=${test_dir#${user_job_dir}/}
 
245
 
 
246
  # ensure files in this directory are accessible since
 
247
  # mktemp sets directory perms to 0700 regardless of umask.
 
248
  cmd="chmod 755 \"$test_dir\""
 
249
  eval "$cmd"
 
250
  TEST_EQ "$cmd" $? 0
 
251
 
 
252
  TEST_NE "HOME" "$HOME" ""
 
253
}
 
254
 
 
255
cleanup()
 
256
{
 
257
  if [ -d "$test_dir" ]
 
258
  then
 
259
    echo "Removing test directory '$test_dir'"
 
260
    cmd="rmdir \"$test_dir\""
 
261
    eval "$cmd"
 
262
    TEST_EQ "$cmd" $? 0
 
263
  fi
 
264
}
 
265
 
 
266
ensure_job_known()
 
267
{
 
268
  job="$1"
 
269
  job_name="$2"
 
270
 
 
271
  [ -z "$job" ] && die "no job"
 
272
  [ -z "$job_name" ] && die "no job name"
 
273
 
 
274
  TEST_FEATURE "ensure 'initctl' recognises job"
 
275
  initctl list|grep -q "^$job " || \
 
276
    TEST_FAILED "job $job_name not known to initctl"
 
277
 
 
278
  TEST_FEATURE "ensure 'status' recognises job"
 
279
  cmd="status ${job}"
 
280
  eval "$cmd" >/dev/null 2>&1
 
281
  rc=$?
 
282
  TEST_EQ "$cmd" $rc 0
 
283
}
 
284
 
 
285
# Note that if the specified job is *not* as task, it is expected to run
 
286
# indefinately. This allows us to perform PID checks, etc.
 
287
run_user_job_tests()
 
288
{
 
289
  job_name="$1"
 
290
  job_file="$2"
 
291
  task="$3"
 
292
  env="$4"
 
293
 
 
294
  # XXX: env can be empty
 
295
  [ -z "$job_name" ] && die "no job name"
 
296
  [ -z "$job_file" ] && die "no job file"
 
297
  [ -z "$task" ] && die "no task value"
 
298
 
 
299
  job="${test_dir_suffix}/${job_name}"
 
300
 
 
301
  [ -f "$job_file" ] || TEST_FAILED "job file '$job_file' does not exist"
 
302
 
 
303
  ensure_job_known "$job" "$job_name"
 
304
 
 
305
  TEST_FEATURE "ensure job can be started"
 
306
  cmd="start ${job} ${env}"
 
307
  output=$(eval "$cmd")
 
308
  rc=$?
 
309
  TEST_EQ "$cmd" $rc 0
 
310
 
 
311
  if [ "$task" = no ]
 
312
  then
 
313
    TEST_FEATURE "ensure 'start' shows job pid"
 
314
    pid=$(echo "$output"|awk '{print $4}')
 
315
    TEST_NE "pid" "$pid" ""
 
316
 
 
317
    TEST_FEATURE "ensure 'initctl' shows job is running with pid"
 
318
    initctl list|grep -q "^$job start/running, process $pid" || \
 
319
      TEST_FAILED "job $job_name did not start"
 
320
 
 
321
    TEST_FEATURE "ensure 'status' shows job is running with pid"
 
322
    cmd="status ${job}"
 
323
    output=$(eval "$cmd")
 
324
    echo "$output"|while read job_tmp state ignored status_pid
 
325
    do
 
326
      state=$(echo $state|tr -d ',')
 
327
      TEST_EQ "job name"  "$job_tmp" "$job"
 
328
      TEST_EQ "job state" "$state" "start/running"
 
329
      TEST_EQ "job pid"   "$status_pid" "$pid"
 
330
    done
 
331
 
 
332
    TEST_FEATURE "ensure job pid is running with correct uids"
 
333
    pid_uids=$(ps --no-headers -p $pid -o euid,ruid)
 
334
    for pid_uid in $pid_uids
 
335
    do
 
336
      TEST_EQ "pid uid" "$pid_uid" "$uid"
 
337
    done
 
338
 
 
339
    TEST_FEATURE "ensure job pid is running with correct gids"
 
340
    pid_gids=$(ps --no-headers -p $pid -o egid,rgid)
 
341
    for pid_gid in $pid_gids
 
342
    do
 
343
      TEST_EQ "pid gid" "$pid_gid" "$gid"
 
344
    done
 
345
 
 
346
    TEST_FEATURE "ensure process is running in correct directory"
 
347
    cwd=$(readlink /proc/$pid/cwd)
 
348
    TEST_EQ "cwd" "$cwd" "$HOME"
 
349
 
 
350
    TEST_FEATURE "ensure job can be stopped"
 
351
    cmd="stop ${job}"
 
352
    output=$(eval "$cmd")
 
353
    rc=$?
 
354
    TEST_EQ "$cmd" $rc 0
 
355
 
 
356
    TEST_FEATURE "ensure job pid no longer exists"
 
357
    pid_ids=$(ps --no-headers -p $pid -o euid,ruid,egid,rgid)
 
358
    TEST_EQ "pid uids+gids" "$pid_ids" ""
 
359
  fi
 
360
 
 
361
  remove_job_file "$job_file"
 
362
  ensure_job_gone "$job" "$job_name" "$env"
 
363
}
 
364
 
 
365
remove_job_file()
 
366
{
 
367
  job_file="$1"
 
368
 
 
369
  [ -z "$job_file" ] && die "no job file"
 
370
  [ ! -f "$job_file" ] && TEST_FAILED "job file '$job_file' does not exist"
 
371
 
 
372
  cmd="rm $job_file"
 
373
  eval "$cmd"
 
374
  TEST_EQ "$cmd" $? 0
 
375
}
 
376
 
 
377
ensure_job_gone()
 
378
{
 
379
  job="$1"
 
380
  job_name="$2"
 
381
  env="$3"
 
382
 
 
383
  # XXX: no check on env since it can be empty
 
384
  [ -z "$job" ] && die "no job"
 
385
  [ -z "$job_name" ] && die "no job name"
 
386
 
 
387
  TEST_FEATURE "ensure 'initctl' no longer recognises job"
 
388
  initctl list|grep -q "^$job " && \
 
389
    TEST_FAILED "deleted job $job_name still known to initctl"
 
390
 
 
391
  TEST_FEATURE "ensure 'status' no longer recognises job"
 
392
  cmd="status ${job}"
 
393
  eval "$cmd" >/dev/null 2>&1
 
394
  rc=$?
 
395
  TEST_NE "$cmd" $rc 0
 
396
}
 
397
 
 
398
test_user_job()
 
399
{
 
400
  test_group="$1"
 
401
  job_name="$2"
 
402
  script="$3"
 
403
  task="$4"
 
404
  env="$5"
 
405
 
 
406
  # XXX: no test on script or env since they might be empty
 
407
  [ -z "$test_group" ] && die "no test group"
 
408
  [ -z "$job_name" ] && die "no job name"
 
409
  [ -z "$task" ] && die "no task"
 
410
 
 
411
  TEST_GROUP "$test_group"
 
412
 
 
413
  job_file="${test_dir}/${job_name}.conf"
 
414
 
 
415
  echo "$script" > $job_file
 
416
 
 
417
  run_user_job_tests "$job_name" "$job_file" "$task" "$env"
 
418
}
 
419
 
 
420
test_user_job_binary()
 
421
{
 
422
  group="user job running a binary"
 
423
  job_name="binary_test"
 
424
  script="exec sleep 999"
 
425
  test_user_job "$group" "$job_name" "$script" no ""
 
426
}
 
427
 
 
428
test_user_job_binary_task()
 
429
{
 
430
  group="user job running a binary task"
 
431
  job_name="binary_task_test"
 
432
  OUTFILE=$(mktemp)
 
433
 
 
434
  script="\
 
435
task
 
436
exec /bin/true > $OUTFILE"
 
437
 
 
438
  test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
 
439
  rm -f $OUTFILE
 
440
}
 
441
 
 
442
test_user_job_single_line_script()
 
443
{
 
444
  group="user job running a single-line script"
 
445
  job_name="single_line_script_test"
 
446
  script="\
 
447
script
 
448
  sleep 999
 
449
end script"
 
450
  test_user_job "$group" "$job_name" "$script" no ""
 
451
}
 
452
 
 
453
test_user_job_single_line_script_task()
 
454
{
 
455
  group="user job running a single-line script task"
 
456
  job_name="single_line_script_task_test"
 
457
  OUTFILE=$(mktemp)
 
458
 
 
459
  script="\
 
460
task
 
461
script
 
462
  exec /bin/true > $OUTFILE
 
463
end script"
 
464
  test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
 
465
  rm -f $OUTFILE
 
466
}
 
467
 
 
468
test_user_job_multi_line_script()
 
469
{
 
470
  group="user job running a multi-line script"
 
471
  job_name="multi_line_script_test"
 
472
  script="\
 
473
script
 
474
 
 
475
  /bin/true
 
476
  /bin/true;/bin/true
 
477
  sleep 999
 
478
 
 
479
end script"
 
480
  test_user_job "$group" "$job_name" "$script" no ""
 
481
}
 
482
 
 
483
test_user_job_multi_line_script_task()
 
484
{
 
485
  group="user job running a multi-line script task"
 
486
  job_name="multi_line_script_task_test"
 
487
  OUTFILE=$(mktemp)
 
488
 
 
489
  script="\
 
490
task
 
491
script
 
492
 
 
493
  /bin/true
 
494
  /bin/true
 
495
  /bin/true
 
496
 
 
497
end script"
 
498
  test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE"
 
499
  rm -f $OUTFILE
 
500
}
 
501
 
 
502
test_user_emit_events()
 
503
{
 
504
  job_name="start_on_foo"
 
505
 
 
506
  TEST_GROUP "user emitting an event"
 
507
  initctl emit foo || TEST_FAILED "failed to emit event as user"
 
508
 
 
509
  TEST_GROUP "user emitting an event to start a job"
 
510
  script="\
 
511
    start on foo BAR=2
 
512
    stop on baz cow=moo or hello
 
513
    exec sleep 999"
 
514
 
 
515
  job_file="${test_dir}/${job_name}.conf"
 
516
  job="${test_dir_suffix}/${job_name}"
 
517
 
 
518
  echo "$script" > $job_file
 
519
 
 
520
  ensure_job_known "$job" "$job_name"
 
521
 
 
522
  initctl list|grep -q "^$job stop/waiting" || \
 
523
      TEST_FAILED "job $job_name not stopped"
 
524
 
 
525
  TEST_FEATURE "ensure job can be started with event"
 
526
  initctl emit foo BAR=2 || \
 
527
    TEST_FAILED "failed to emit event for user job"
 
528
 
 
529
  initctl status "$job"|grep -q "^$job start/running" || \
 
530
      TEST_FAILED "job $job_name failed to start"
 
531
 
 
532
  TEST_FEATURE "ensure job can be stopped with event"
 
533
  initctl emit baz cow=moo || \
 
534
    TEST_FAILED "failed to emit event for user job"
 
535
 
 
536
  initctl list|grep -q "^$job stop/waiting" || \
 
537
      TEST_FAILED "job $job_name not stopped"
 
538
 
 
539
  rm -f "$job_file"
 
540
}
 
541
 
 
542
test_user_job_setuid_setgid()
 
543
{
 
544
    group="user job with setuid and setgid me"
 
545
    job_name="setuid_setgid_me_test"
 
546
    script="\
 
547
setuid $(id -un)
 
548
setgid $(id -gn)
 
549
exec sleep 999"
 
550
    test_user_job "$group" "$job_name" "$script" no ""
 
551
 
 
552
    TEST_GROUP "user job with setuid and setgid root"
 
553
    script="\
 
554
setuid root
 
555
setgid root
 
556
exec sleep 999"
 
557
 
 
558
    job_name="setuid_setgid_root_test"
 
559
    job_file="${test_dir}/${job_name}.conf"
 
560
    job="${test_dir_suffix}/${job_name}"
 
561
 
 
562
    echo "$script" > $job_file
 
563
 
 
564
    ensure_job_known "$job" "$job_name"
 
565
 
 
566
    TEST_FEATURE "ensure job fails to start as root"
 
567
    cmd="start ${job}"
 
568
    output=$(eval "$cmd" 2>&1)
 
569
    rc=$?
 
570
    TEST_EQ "$cmd" $rc 1
 
571
 
 
572
    TEST_FEATURE "ensure 'start' indicates job failure"
 
573
    error=$(echo "$output"|grep failed)
 
574
    TEST_NE "error" "$error" ""
 
575
 
 
576
    TEST_FEATURE "ensure 'initctl' does not list job"
 
577
    initctl list|grep -q "^$job stop/waiting" || \
 
578
        TEST_FAILED "job $job_name not listed as stopped"
 
579
 
 
580
    delete_job "$job_name"
 
581
}
 
582
 
 
583
get_job_file()
 
584
{
 
585
  job_name="$1"
 
586
 
 
587
  [ -z "$job_name" ] && die "no job name"
 
588
  echo "${test_dir}/${job_name}.conf"
 
589
}
 
590
 
 
591
ensure_no_output()
 
592
{
 
593
  job_name="$1"
 
594
  script="$2"
 
595
  instance="$3"
 
596
 
 
597
  job="${test_dir_suffix}/${job_name}"
 
598
 
 
599
  create_job "$job_name" "$script"
 
600
  start_job "$job" "$job_name" "$instance"
 
601
 
 
602
  check_job_output "$job_name"
 
603
  delete_job "$job_name"
 
604
}
 
605
 
 
606
create_job()
 
607
{
 
608
  job_name="$1"
 
609
  script="$2"
 
610
 
 
611
  # XXX: script could be empty
 
612
  [ -z "$job_name" ] && die "no job name"
 
613
 
 
614
  debug "create_job: job_name='$job_name'"
 
615
  debug "create_job: script='$script'"
 
616
 
 
617
  # Not currently possible to have a user job with the
 
618
  # same name as a system job.
 
619
  #
 
620
  # XXX: Note that this test assumes that user has *not* specified
 
621
  # XXX: an alternate configuration directory using the
 
622
  # XXX: '--confdir' option.
 
623
  [ -e "${sys_job_dir}/${job_name}.conf" ] && \
 
624
    die "job '$job_name' already exists as a system job"
 
625
 
 
626
  job_file="${test_dir}/${job_name}.conf"
 
627
  job="${test_dir_suffix}/${job_name}"
 
628
 
 
629
  echo "$script" > "$job_file"
 
630
  sync
 
631
}
 
632
 
 
633
delete_job()
 
634
{
 
635
  job_name="$1"
 
636
 
 
637
  [ -z "$job_name" ] && die "no job name"
 
638
 
 
639
  job_file="$(get_job_file $job_name)"
 
640
 
 
641
  rm "$job_file" || TEST_FAILED "unable to remove job file '$job_file'"
 
642
}
 
643
 
 
644
check_job_output()
 
645
{
 
646
  job_name="$1"
 
647
 
 
648
  [ ! -z "$(ls $user_log_dir 2>/dev/null)" ] && \
 
649
    TEST_FAILED "job $job_name created logfile unexpectedly in '$user_log_dir'"
 
650
 
 
651
  # XXX: note that it might appear that checking in $sys_log_dir
 
652
  # could result in false positives, but this isn't so since
 
653
  # (currently) it is not possible for a user job to have the
 
654
  # same name as a system job. start_job() will detect this
 
655
  # scenario.
 
656
  for dir in "$user_log_dir" "$sys_log_dir"
 
657
  do
 
658
    log_file="${dir}/${job_name}.log"
 
659
    [ -f "$log_file" ] && \
 
660
      TEST_FAILED "job $job_name created logfile unexpectedly as '$log_file'"
 
661
  done
 
662
}
 
663
 
 
664
start_job()
 
665
{
 
666
  job="$1"
 
667
  job_file="$2"
 
668
  instance="$3"
 
669
  allow_failure="$4"
 
670
 
 
671
  # XXX: instance may be blank
 
672
  [ -z "$job" ] && die "no job"
 
673
  [ -z "$job_file" ] && die "no job file"
 
674
 
 
675
  debug "start_job: job='$job'"
 
676
  debug "start_job: job_file='$job_file'"
 
677
  debug "start_job: instance='$instance'"
 
678
  debug "start_job: allow_failure='$allow_failure'"
 
679
 
 
680
  eval output=$(mktemp)
 
681
 
 
682
  # XXX: Don't quote instance as we don't want to pass a null instance to
 
683
  # start(8).
 
684
  cmd="start \"$job\" $instance >${output} 2>&1"
 
685
  debug "start_job: running '$cmd'"
 
686
  eval "$cmd"
 
687
  rc=$?
 
688
 
 
689
  if [ $rc -ne 0 -a -z "$allow_failure" ]
 
690
  then
 
691
    TEST_FAILED "job $job_file not started: $(cat $output)"
 
692
  fi
 
693
 
 
694
  rm -f "$output"
 
695
}
 
696
 
 
697
get_job_logfile_name()
 
698
{
 
699
  job_name="$1"
 
700
  instance_value="$2"
 
701
 
 
702
  # XXX: instance may be null
 
703
  [ -z "$job_name" ] && die "no job name"
 
704
 
 
705
  encoded_test_dir_suffix=$(upstart_encode "${test_dir_suffix}/")
 
706
  file_name="${encoded_test_dir_suffix}$(make_log_name $job_name)"
 
707
 
 
708
  if [ ! -z "$instance_value" ]
 
709
  then
 
710
    log_file="${user_log_dir}/${file_name}-${instance_value}.log"
 
711
  else
 
712
    log_file="${user_log_dir}/${file_name}.log"
 
713
  fi
 
714
 
 
715
  echo "$log_file"
 
716
}
 
717
 
 
718
run_job()
 
719
{
 
720
  job="$1"
 
721
  job_name="$2"
 
722
  script="$3"
 
723
  instance="$4"
 
724
 
 
725
  # XXX: script, instance might be blank
 
726
  [ -z "$job" ] && die "no job"
 
727
  [ -z "$job_name" ] && die "no job name"
 
728
 
 
729
  debug "run_job: job='$job'"
 
730
  debug "run_job: job_name='$job_name'"
 
731
  debug "run_job: script='$script'"
 
732
  debug "run_job: instance='$instance'"
 
733
 
 
734
  create_job "$job_name" "$script"
 
735
  start_job "$job" "$job_name" "$instance"
 
736
}
 
737
 
 
738
ensure_file_meta()
 
739
{
 
740
  file="$1"
 
741
  expected_owner="$2"
 
742
  expected_group="$3"
 
743
  expected_perms="$4"
 
744
 
 
745
  [ -z "$file" ] && die "no file"
 
746
  [ -z "$expected_owner" ] && die "no expected owner"
 
747
  [ -z "$expected_group" ] && die "no expected group"
 
748
  [ -z "$expected_perms" ] && die "no expected perms"
 
749
 
 
750
  [ ! -f "$file" ] && die "file $file does not exist"
 
751
 
 
752
  expected_perms="640"
 
753
  umask_value=$(umask)
 
754
  umask_expected=0022
 
755
 
 
756
  if [ "$umask_value" != "$umask_expected" ]
 
757
  then
 
758
    msg="umask value is $umask_value -"
 
759
    msg="${msg} changing it to $umask_expected."
 
760
    echo "WARNING: $msg"
 
761
    umask "$umask_expected" || TEST_FAILED "unable to change umask"
 
762
  fi
 
763
 
 
764
  owner=$(ls -l "$file"|awk '{print $3}')
 
765
  group=$(ls -l "$file"|awk '{print $4}')
 
766
  perms=$(stat --printf "%a\n" "$file")
 
767
 
 
768
  [ "$owner" = "$expected_owner" ] || TEST_FAILED \
 
769
    "file $file has wrong owner (expected $expected_owner, got $owner)"
 
770
 
 
771
  [ "$group" = "$expected_group" ] || TEST_FAILED \
 
772
    "file $file has wrong group (expected $expected_group, got $group)"
 
773
 
 
774
  [ "$perms" = "$expected_perms" ] || TEST_FAILED \
 
775
    "file $file has wrong group (expected $expected_perms, got $perms)"
 
776
}
 
777
 
 
778
 
 
779
ensure_output()
 
780
{
 
781
  job_name="$1"
 
782
  script="$2"
 
783
  expected_output="$3"
 
784
  instance="$4"
 
785
  instance_value="$5"
 
786
  options="$6"
 
787
 
 
788
  # XXX: remaining args could be null
 
789
  [ -z "$job_name" ] && die "no job name"
 
790
 
 
791
  debug "ensure_output: job_name='$job_name'"
 
792
  debug "ensure_output: script='$script'"
 
793
  debug "ensure_output: expected_ouput='$expected_ouput'"
 
794
  debug "ensure_output: instance='$instance'"
 
795
  debug "ensure_output: instance_value='$instance_value'"
 
796
  debug "ensure_output: options='$options'"
 
797
 
 
798
  regex=n
 
799
  retain=n
 
800
  unique=""
 
801
  use_od=n
 
802
 
 
803
  for opt in $options
 
804
  do
 
805
    case "$opt" in
 
806
      regex)
 
807
        regex=y
 
808
        ;;
 
809
      retain)
 
810
        retain=y
 
811
        ;;
 
812
      unique)
 
813
        unique='|sort -u'
 
814
        ;;
 
815
      use_od)
 
816
        use_od=y
 
817
        ;;
 
818
    esac
 
819
  done
 
820
 
 
821
  debug "ensure_output: regex='$regex'"
 
822
  debug "ensure_output: retain='$retain'"
 
823
  debug "ensure_output: unique='$unique'"
 
824
  debug "ensure_output: use_od='$use_od'"
 
825
 
 
826
  expected_owner=$(id -un)
 
827
  expected_group=$(id -gn)
 
828
  expected_perms="640"
 
829
 
 
830
  job="${test_dir_suffix}/${job_name}"
 
831
 
 
832
  run_job "$job" "$job_name" "$script" "$instance"
 
833
 
 
834
  debug "ensure_output: user_log_dir='$user_log_dir'"
 
835
  debug "ensure_output: test_dir='$test_dir'"
 
836
  debug "ensure_output: test_dir_suffix='$test_dir_suffix'"
 
837
 
 
838
  log_file=$(get_job_logfile_name "$job_name" "$instance_value")
 
839
 
 
840
  debug "ensure_output: log_file='$log_file'"
 
841
 
 
842
  # Give Upstart a chance to parse the file
 
843
  count=1
 
844
  while ! status "$job" >/dev/null 2>&1
 
845
  do
 
846
    sleep 1
 
847
    count=$((count+1))
 
848
    [ "$count" -eq 5 ] && break
 
849
  done
 
850
 
 
851
  # give job a chance to start
 
852
  count=1
 
853
  while [ ! -f "$log_file" ]
 
854
  do
 
855
    sleep 1
 
856
    count=$((count+1))
 
857
    [ "$count" -eq 5 ] && break
 
858
  done
 
859
 
 
860
  [ ! -f "$log_file" ] && \
 
861
      TEST_FAILED "job '$job_name' failed to create logfile"
 
862
 
 
863
  ensure_file_meta \
 
864
    "$log_file" \
 
865
    "$expected_owner" \
 
866
    "$expected_group" \
 
867
    "$expected_perms"
 
868
 
 
869
  # XXX: note we have to remove carriage returns added by the line
 
870
  # discipline
 
871
  if [ "$regex" = y ]
 
872
  then
 
873
    log=$(eval "cat $log_file|tr -d '\r' $unique")
 
874
    msg="job '$job_name' failed to log correct data\n"
 
875
    msg="${msg}\texpected regex: '$expected_output'\n"
 
876
    msg="${msg}\tgot           : '$log'"
 
877
    cat "$log_file" | egrep "$expected_output" || TEST_FAILED "$msg"
 
878
  elif [ "$use_od" = y ]
 
879
  then
 
880
    log=$(eval "cat $log_file|tr -d '\r' $unique|od -x")
 
881
    msg="job '$job_name' failed to log correct data\n"
 
882
    msg="${msg}\texpected hex: '$expected_output'\n"
 
883
    msg="${msg}\tgot         : '$log'"
 
884
    [ "$expected_output" != "$log" ] && TEST_FAILED "$msg"
 
885
  else
 
886
    log=$(eval "cat $log_file|tr -d '\r' $unique")
 
887
    msg="job '$job_name' failed to log correct data\n"
 
888
    msg="${msg}\texpected text: '$expected_output'\n"
 
889
    msg="${msg}\tgot          : '$log'"
 
890
    [ "$expected_output" != "$log" ] && TEST_FAILED "$msg"
 
891
  fi
 
892
 
 
893
  if [ "$retain" = n ]
 
894
  then
 
895
    delete_job "$job_name"
 
896
    rm "$log_file" || TEST_FAILED "unable to remove log file '$log_file'"
 
897
  fi
 
898
}
 
899
 
 
900
test_ensure_no_unexpected_output()
 
901
{
 
902
  #---------------------------------------------------------------------
 
903
  feature="ensure command job does not create log file with no console"
 
904
  TEST_FEATURE "$feature"
 
905
 
 
906
  job_name=$(make_job_name "$feature")
 
907
 
 
908
  script="\
 
909
    console none
 
910
    exec echo hello world"
 
911
 
 
912
  ensure_no_output "$job_name" "$script" ""
 
913
 
 
914
  #---------------------------------------------------------------------
 
915
  feature="ensure 1-line script job does not create log file with no console"
 
916
  TEST_FEATURE "$feature"
 
917
 
 
918
  job_name=$(make_job_name "$feature")
 
919
 
 
920
  script="\
 
921
    console none
 
922
    script
 
923
      echo hello world
 
924
    end script
 
925
  "
 
926
 
 
927
  ensure_no_output "$job_name" "$script" ""
 
928
 
 
929
  #---------------------------------------------------------------------
 
930
  feature="ensure multi-line script job does not create log file with no console"
 
931
  TEST_FEATURE "$feature"
 
932
 
 
933
  job_name=$(make_job_name "$feature")
 
934
 
 
935
  script="\
 
936
    console none
 
937
    script
 
938
      /bin/true
 
939
      echo hello world
 
940
    end script
 
941
  "
 
942
 
 
943
  ensure_no_output "$job_name" "$script" ""
 
944
 
 
945
  #---------------------------------------------------------------------
 
946
  feature="ensure no output if log directory does not exist"
 
947
  TEST_FEATURE "$feature"
 
948
 
 
949
  rmdir "${user_log_dir}" || \
 
950
    TEST_FAILED "unable to delete log directory '$user_log_dir'"
 
951
 
 
952
  job_name=$(make_job_name "$feature")
 
953
  string="hello world"
 
954
  script="\
 
955
    console log
 
956
    script
 
957
      /bin/true
 
958
      /bin/echo hello world
 
959
    end script
 
960
  "
 
961
 
 
962
  ensure_no_output "$job_name" "$script" ""
 
963
 
 
964
  mkdir "${user_log_dir}" || \
 
965
    TEST_FAILED "unable to recreate log directory '$user_log_dir'"
 
966
 
 
967
  #---------------------------------------------------------------------
 
968
  feature="ensure command job does not create log file with invalid command"
 
969
  TEST_FEATURE "$feature"
 
970
 
 
971
  job_name=$(make_job_name "$feature")
 
972
 
 
973
  script="\
 
974
    console log
 
975
    exec /this/command/does/not/exist"
 
976
 
 
977
  job="${test_dir_suffix}/${job_name}"
 
978
  create_job "$job_name" "$script"
 
979
  start_job "$job" "$job_name" "" 1
 
980
  check_job_output "$job_name"
 
981
  delete_job "$job_name"
 
982
}
 
983
 
 
984
test_output_logged()
 
985
{
 
986
  # XXX: upstart won't create this
 
987
  mkdir -p "$user_log_dir"
 
988
 
 
989
  test_ensure_no_unexpected_output
 
990
}
 
991
 
 
992
test_user_jobs()
 
993
{
 
994
  test_user_job_binary
 
995
  test_user_job_single_line_script
 
996
  test_user_job_multi_line_script
 
997
 
 
998
  test_user_job_binary_task
 
999
  test_user_job_single_line_script_task
 
1000
  test_user_job_multi_line_script_task
 
1001
 
 
1002
  test_user_job_setuid_setgid
 
1003
 
 
1004
  test_user_emit_events
 
1005
 
 
1006
  test_output_logged
 
1007
}
 
1008
 
 
1009
tests()
 
1010
{
 
1011
  echo
 
1012
  echo -n "Running Upstart user session tests as user '`whoami`'"
 
1013
  echo " (uid $uid, gid $gid) in directory '$test_dir'"
 
1014
  echo
 
1015
 
 
1016
  test_user_jobs
 
1017
 
 
1018
  echo
 
1019
  echo "All tests completed successfully"
 
1020
  echo
 
1021
}
 
1022
 
 
1023
usage()
 
1024
{
 
1025
cat <<EOT
 
1026
USAGE: $script_name [options]
 
1027
 
 
1028
OPTIONS:
 
1029
 
 
1030
 -a        : Actually run this script.
 
1031
 -h        : Show this help.
 
1032
 -u <user> : Specify name of test user to create.
 
1033
 
 
1034
DESCRIPTION:
 
1035
 
 
1036
Run simple set of Upstart user session tests.
 
1037
 
 
1038
PREREQUISITE:
 
1039
 
 
1040
For this test to run, non-root users must be allowed to invoke all D-Bus
 
1041
methods on Upstart via configuration file:
 
1042
 
 
1043
  /etc/dbus-1/system.d/Upstart.conf 
 
1044
 
 
1045
See dbus-daemon(1) for further details.
 
1046
 
 
1047
WARNING: Note that this script is unavoidably invasive, so read what
 
1048
WARNING: follows before running!
 
1049
 
 
1050
If run as a non-root user, this script will create a uniquely-named
 
1051
subdirectory below "\$HOME/.init/" to run its tests in. On successful
 
1052
completion of these tests, the unique subdirectory and its contents will
 
1053
be removed.
 
1054
 
 
1055
If however, this script is invoked as the root user, the script will
 
1056
refuse to run until given the name of a test user to create via the "-u"
 
1057
option. If the user specified to this option already exists, this script
 
1058
will exit with an error. If the user does not already exist, it will be
 
1059
created, the script then run *as that user* and assuming successful
 
1060
completion of the tests, the test user and their home directory will
 
1061
then be deleted.
 
1062
 
 
1063
EOT
 
1064
}
 
1065
 
 
1066
#---------------------------------------------------------------------
 
1067
# main
 
1068
#---------------------------------------------------------------------
 
1069
 
 
1070
while getopts "dhu:" opt
 
1071
do
 
1072
  case "$opt" in
 
1073
    d)
 
1074
      debug_enabled=1
 
1075
    ;;
 
1076
 
 
1077
    h)
 
1078
      usage
 
1079
      exit 0
 
1080
    ;;
 
1081
 
 
1082
    u)
 
1083
      user_to_create="$OPTARG"
 
1084
    ;;
 
1085
  esac
 
1086
done
 
1087
 
 
1088
setup
 
1089
tests
 
1090
cleanup
 
1091
exit 0