You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

726 lines
25 KiB
Python

#!/usr/bin/env python
#
# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# Contact: Nokia Corporation (directui@nokia.com)
#
# This file is part of applauncherd.
#
# If you have questions regarding the use of this file, please contact
# Nokia at directui@nokia.com.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 2.1 as published by the Free Software Foundation
# and appearing in the file LICENSE.LGPL included in the packaging
# of this file.
"""
This program tests the startup time of the given application with and
without launcher.
Requirements:
1. DISPLAY environment variable must be set correctly.
2. DBus session bus must be running.
3. DBus session bus address must be stored in /tmp/session_bus_address.user.
4. Given application supports launcher with .launcher binary in /usr/bin/.
5. launcher application should be installed.
Usage: test-func-launcher <launcherable application>
Example: test-func-launcher /usr/bin/fala_ft_hello
Authors: ext-nimika.1.keshri@nokia.com
ext-oskari.timperi@nokia.com
"""
import os, os.path, glob
import subprocess
import commands
import time
import sys
import unittest
import re
from subprocess import Popen
from utils import *
from os.path import basename
LAUNCHER_BINARY='/usr/bin/applauncherd'
DEV_NULL = file("/dev/null","w")
LAUNCHABLE_APPS = ['/usr/bin/fala_ft_hello','/usr/bin/fala_ft_hello1', '/usr/bin/fala_ft_hello2']
PREFERED_APP = '/usr/bin/fala_ft_hello'
using_scratchbox = False
def start_launcher_daemon():
temp = basename(LAUNCHER_BINARY)
st, op = commands.getstatusoutput("pgrep %s" %temp)
if st == 0:
debug("Launcher already started")
return op
def check_prerequisites():
if os.getenv('DISPLAY') == None:
error("DISPLAY is not set. Check the requirements.")
if os.getenv('DBUS_SESSION_BUS_ADDRESS') == None:
error("DBUS_SESSION_BUS_ADDRESS is not set.\n" +
"You probably want to source /tmp/session_bus_address.user")
for app in LAUNCHABLE_APPS:
assert(len(basename(app)) < 15, "For app: %s, base name !<= 14" % app)
class launcher_tests (unittest.TestCase):
def setUp(self):
#setup here
print "Executing SetUp"
def tearDown(self):
#teardown here
print "Executing TearDown"
#Testcases
def test_001_launcher_exist(self):
"""
To test if the launcher exists and is executable or not
"""
self.assert_(os.path.isfile(LAUNCHER_BINARY), "Launcher file does not exist")
self.assert_(os.access(LAUNCHER_BINARY, os.X_OK), "Launcher exists, but is not executable")
def test_002_applications_exist(self):
"""
test_launchable_application_exists
"""
failed_apps = []
for app in LAUNCHABLE_APPS:
temp = "%s.launch" % app
if not (os.path.isfile(temp) and os.access(temp, os.X_OK)):
failed_apps.append(temp)
self.assert_(failed_apps == [], "Some applications do not have the launch files, list: %s" % str(failed_apps))
def test_003_zombie_state(self):
"""
To test that no Zombie process exist after the application is killed
"""
#launch application with launcher
#check if the application is running
#kill the application (pid = p.pid)
#check if pgrep appname should be nothing
#self.kill_process(LAUNCHER_BINARY)
process_handle = run_app_with_launcher(PREFERED_APP)
process_id = wait_for_app(PREFERED_APP, 5)
print process_id
kill_process(PREFERED_APP)
time.sleep(4)
process_handle = run_app_with_launcher(PREFERED_APP)
process_id1 = wait_for_app(PREFERED_APP, 5)
print process_id1
kill_process(PREFERED_APP)
time.sleep(4)
process_id1 = get_pid(PREFERED_APP)
print process_id1
self.assert_(process_id != process_id1 , "New Process not launched")
self.assert_(process_id1 == None , "Process still running")
def test_004_launch_multiple_apps(self):
"""
To test that more than one applications are launched by the launcher
"""
def kill_launched(pids):
for pid in pids:
kill_process(apppid = pid)
pidlist = []
for app in LAUNCHABLE_APPS:
p = run_app_with_launcher(app)
pid = wait_for_app(app, timeout = 10, sleep = 1)
if pid == None:
kill_launched(pidlist)
self.fail("%s was not launched using applauncherd")
pidlist.append(pid)
kill_launched(pidlist)
def test_005_one_instance(self):
"""
To test that only one instance of a application exist
"""
#launch application
#self.run_app_with_launcher(appname)
#get pid of application
#launch applicatoin again
#check pgrep application
#y = commands.getstatusoutput(pgrep appname)
#len(y[-1].split(' ')) == 1
process_handle = run_app_with_launcher(PREFERED_APP)
process_id = wait_for_app(PREFERED_APP)
debug("PID of first %s" % process_id)
process_handle1 = run_app_with_launcher(PREFERED_APP)
time.sleep(2)
process_id = wait_for_app(PREFERED_APP)
debug("PID of 2nd %s" % process_id)
kill_process(PREFERED_APP)
self.assert_( len(process_id.split(' ')) == 1, "Only one instance of app not running")
def test_006_creds(self):
"""
Test that the fala_ft_creds* applications have the correct
credentials set (check aegis file included in the debian package)
"""
creds1 = launch_and_get_creds('/usr/bin/fala_ft_creds1')
creds2 = launch_and_get_creds('/usr/bin/fala_ft_creds2')
self.assert_(creds1 != None, "couldn't get credentials")
self.assert_(creds2 != None, "couldn't get credentials")
debug("fala_ft_creds1 has %s" % ', '.join(creds1))
debug("fala_ft_creds2 has %s" % ', '.join(creds2))
# required caps for fala_ft_creds1
cap1 = ['tcb', 'drm', 'CAP::setuid', 'CAP::setgid',
'CAP::setfcap']
# required caps for fala_ft_creds2
cap2 = ['Cellular']
# check that all required creds are there
for cap in cap1:
self.assert_(cap in creds1, "%s not set for fala_ft_creds1" % cap)
for cap in cap2:
self.assert_(cap in creds2, "%s not set for fala_ft_creds2" % cap)
def test_007_no_aegis_Bug170905(self):
"""
Check that an application that doesn't have aegis file doesn't
get any funny credentials.
"""
creds = launch_and_get_creds('/usr/bin/fala_ft_hello')
debug("fala_ft_hello has %s" % ', '.join(creds))
self.assert_(creds != None, "error retrieving credentials")
# Credentials should be dropped, but uid/gid retained
req_creds = ['UID::user', 'GID::users']
creds.sort()
req_creds.sort()
self.assert_(creds == req_creds, "fala_ft_hello has differnt creds set!")
def test_008_invoker_creds(self):
"""
Test that the launcher registered customized credentials
and invoker has proper credentials to access launcher
"""
INVOKER_BINARY='/usr/bin/invoker'
FAKE_INVOKER_BINARY='/usr/bin/faulty_inv'
#test application used for testing invoker
Testapp = '/usr/bin/fala_ft_hello.launch'
#launching the testapp with actual invoker
st = os.system('%s --type=m %s'%(INVOKER_BINARY, Testapp))
pid = get_pid(Testapp.replace('.launch', ''))
self.assert_((st == 0), "Application was not launched using launcher")
self.assert_(not (pid == None), "Application was not launched using launcher: actual pid%s" %pid)
print pid
#self.kill_process(Testapp.replace('.launch', ''))
kill_process(apppid=pid)
pid = get_pid(Testapp.replace('.launch', ''))
self.assert_((pid == None), "Application still running")
#launching the testapp with fake invoker
st = os.system('%s --type=m %s'%(FAKE_INVOKER_BINARY, Testapp))
pid = get_pid(Testapp.replace('.launch', ''))
self.assert_(not (st == 0), "Application was launched using fake launcher")
self.assert_((pid == None), "Application was launched using fake launcher")
def test_009_launch_multiple_apps_cont(self):
"""
To test that more than one applications are launched by the launcher
"""
for app in LAUNCHABLE_APPS:
#launch application with launcher
#check if the application is running
#check if p.pid is same as pgrep appname
#in a global dictionary, append the pid
process_handle = run_app_with_launcher(app)
time.sleep(8)
process_id = get_pid('fala_ft_hello')
pid_list = process_id.split()
self.assert_(len(pid_list) == len(LAUNCHABLE_APPS), "All Applications were not launched using launcher")
for pid in pid_list:
kill_process(apppid=pid)
def test_010(self):
"""
NB#179266
When calling invoker with --wait-term and killing invoker,
the launched application should die too.
"""
invoker = '/usr/bin/invoker'
app_path = '/usr/bin/fala_ft_hello.launch'
# Launch the app with invoker
p = subprocess.Popen(('%s --type=m --wait-term %s' % (invoker, app_path)).split(),
shell = False,
stdout = DEV_NULL, stderr = DEV_NULL)
# Retrieve their pids
invoker_pid = wait_for_app('invoker')
app_pid = wait_for_app('fala_ft_hello')
# Make sure that both apps started
self.assert_(invoker_pid != None, "invoker not executed?")
self.assert_(app_pid != None, "%s not launched by invoker?" % app_path)
# Send SIGTERM to invoker, the launched app should die
kill_process(None, invoker_pid, 15)
time.sleep(2)
# This should be None
app_pid2 = get_pid('fala_ft_hello')
if (app_pid2 != None):
kill_process(None, app_pid2)
self.assert_(False, "%s was not killed" % app_path)
def test_011(self):
"""
Test that the --daemon parameter works for applauncherd
"""
# function to remove some temporaries
def rem():
files = ['/tmp/applauncherd.lock'] + glob.glob('/tmp/boost*')
for f in files:
print "removing %s" % f
try:
os.remove(f)
except:
pass
# stop applauncherd if it's running
if not using_scratchbox:
commands.getstatusoutput("initctl stop xsession/applauncherd")
# and for the fun of it let's do it again
commands.getstatusoutput("pkill applauncherd")
rem()
# start applauncherd daemonized
p = subprocess.Popen(["/usr/bin/applauncherd.bin", "--daemon"],
shell=False,
stdout=DEV_NULL, stderr=DEV_NULL)
time.sleep(3)
st, op = commands.getstatusoutput('pgrep -lf "applauncherd.bin --daemon"')
print op
# filter some cruft out from the output and see how many
# instances are running
op = filter(lambda x: x.find("sh ") == -1, op.split("\n"))
count = len(op)
print "count = %d" % count
self.assert_(count == 1, "applauncherd was not daemonized (or too many instances running ..)")
# try to launch an app
run_app_with_launcher('/usr/bin/fala_ft_hello')
time.sleep(2)
pid = wait_for_app('fala_ft_hello')
if pid != None:
kill_process(apppid = pid)
else:
self.assert_(False, "fala_ft_hello was not launched!")
# only the daemonized applauncherd should be running now
commands.getstatusoutput('pkill applauncherd')
rem()
# start applauncherd again
if using_scratchbox:
subprocess.Popen("/usr/bin/applauncherd",
shell=False,
stdout=DEV_NULL, stderr=DEV_NULL)
else:
commands.getstatusoutput("initctl start xsession/applauncherd")
def test_012(self):
"""
Test the --delay parameter of the invoker.
"""
# launch an app with invoker --delay n
print "launching fala_ft_hello ..."
p = Popen(['/usr/bin/invoker', '--delay', '10', '--type=m',
'/usr/bin/fala_ft_hello.launch'],
shell=False,
stdout=DEV_NULL, stderr=DEV_NULL)
# wait a little
print "waiting ..."
time.sleep(5)
success = True
if p.poll() == None:
print "NOT DEAD"
else:
print "DEAD"
success = False
print "waiting for invoker to terminate ..."
p.wait()
print "terminating fala_ft_hello ..."
Popen(['pkill', 'fala_ft_hello']).wait()
self.assert_(success, "invoker terminated before delay elapsed")
def test_013_applauncherd_usage(self):
"""
Test applauncherd.bin help
"""
st, op = commands.getstatusoutput("applauncherd.bin --help")
self.assert_(st == 0, "Usage not printed")
str = op.split('\n')
self.assert_(str[0] == 'Usage: applauncherd [options]', "usage not printed properly")
def test_014_fd_booster_m(self):
"""
File descriptor test for booster-m
"""
count = get_file_descriptor("booster-m","m")
self.assert_(count != 0, "None of the file descriptors were changed")
def test_015_fd_booster_q(self):
"""
File descriptor test for booster-q
"""
count = get_file_descriptor("booster-q","qt")
self.assert_(count != 0, "None of the file descriptors were changed")
def test_016_restart_booster(self):
"""
Test that booster is restarted if it is killed
"""
#get the pids of boosters and make sure they are running
qpid = get_pid('booster-q')
print "Pid of booster-q before killing :%s" %qpid
self.assert_(qpid != None, "No booster process running")
mpid = get_pid('booster-m')
print "Pid of booster-m before killing :%s" %mpid
self.assert_(mpid != None, "No booster process running")
#Kill the booster processes
kill_process(apppid=qpid)
kill_process(apppid=mpid)
#wait for the boosters to be restarted
time.sleep(6)
#check that the new boosters are started
qpid_new = get_pid('booster-q')
print "Pid of booster-q after killing :%s" %qpid_new
self.assert_(qpid_new != None, "No booster process running")
self.assert_(qpid_new != qpid, "booster process was not killed")
mpid_new = get_pid('booster-m')
print "Pid of booster-m after killing :%s" %mpid_new
self.assert_(mpid_new != None, "No booster process running")
self.assert_(mpid_new != mpid, "booster process was not killed")
def test_017_invoker_exit_status(self):
"""
To test that invoker returns the same exit status as the application
"""
#Run application without invoker and get the exit status
st, op = commands.getstatusoutput('/usr/bin/fala_status.launch')
app_st_wo_inv = os.WEXITSTATUS(st)
#Run application with invoker and get the exit status
st, op = commands.getstatusoutput('invoker --type=m --wait-term /usr/bin/fala_status.launch')
app_st_w_inv = os.WEXITSTATUS(st)
self.assert_(app_st_wo_inv == app_st_w_inv, "The invoker returns a wrong exit status")
def test_018_invoker_gid_uid(self):
"""
To Test that the set gid and uid is passed from invoker process to launcher
"""
#get the id in user mode
print ("In User Mode \n")
st, op = commands.getstatusoutput('su user -c ' "id")
usr_id1 = op.split(' ')[0].split('(')[0]
grp_id1 = op.split(' ')[1].split('(')[0]
print("System %s \nSyetem %s" %(usr_id1, grp_id1))
#get id by running the application using invoker in user mode
app = "invoker --type=m /usr/bin/fala_status.launch"
st, op = commands.getstatusoutput('su user -c "%s"' %app );
usr_id = op.split('\n')[1]
grp_id = op.split('\n')[2]
print("Invoker %s \nInvoker %s" %(usr_id, grp_id))
#get id by running the application without invoker in user mode
app = "/usr/bin/fala_status.launch"
st, op = commands.getstatusoutput('su user -c "%s"' %app );
usr_id2 = op.split('\n')[3]
grp_id2 = op.split('\n')[4]
print("Application %s \nApplication %s" %(usr_id2, grp_id2))
self.assert_(usr_id == usr_id1, "The correct UID is not passed by invoker")
self.assert_(grp_id == grp_id1, "The correct GID is not passed by invoker")
self.assert_(usr_id == usr_id2, "The correct UID is not passed by invoker")
self.assert_(grp_id == grp_id2, "The correct GID is not passed by invoker")
#get the id in root mode
print ("In Root Mode \n")
st, op = commands.getstatusoutput("id")
usr_id1 = op.split(' ')[0].split('(')[0]
grp_id1 = op.split(' ')[1].split('(')[0]
print("System %s \nSyetem %s" %(usr_id1, grp_id1))
#get id by running the application using invoker in root mode
app = "invoker --type=m /usr/bin/fala_status.launch"
st, op = commands.getstatusoutput("%s" %app );
usr_id = op.split('\n')[1]
grp_id = op.split('\n')[2]
print("Invoker %s \nInvoker %s" %(usr_id, grp_id))
#get id by running the application without invoker in root mode
app = "/usr/bin/fala_status.launch"
st, op = commands.getstatusoutput("%s" %app );
usr_id2 = op.split('\n')[3]
grp_id2 = op.split('\n')[4]
print("Application %s \nApplication %s" %(usr_id2, grp_id2))
self.assert_(usr_id == usr_id1, "The correct UID is not passed by invoker")
self.assert_(grp_id == grp_id1, "The correct GID is not passed by invoker")
self.assert_(usr_id == usr_id2, "The correct UID is not passed by invoker")
self.assert_(grp_id == grp_id2, "The correct GID is not passed by invoker")
def test_019_signal_forwarding(self):
"""
To test that invoker is killed by the same signal as the application
"""
st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/fala_sf.py")
print ("The Invoker killed by : %s" %op)
self.assert_(op == 'Segmentation fault (core dumped)', "The invoker was not killed by the same signal")
def test_020_launch_wo_applauncherd(self):
"""
To Test that invoker can launch applications even when the applauncherd is not running
"""
#Stop applauncherd
os.system("initctl stop xsession/applauncherd")
time.sleep(1)
#Try to launch an application using invoker
os.system('invoker --type=m /usr/bin/fala_ft_hello.launch &')
time.sleep(3)
process_id1 = get_pid('fala_ft_hello')
self.assert_(process_id1 != None , "application not launcherd running")
time.sleep(1)
kill_process(PREFERED_APP)
os.system("initctl start xsession/applauncherd")
def test_021(self):
"""
Compare the credentials of invoker and the launched application
when applauncherd is running and when it's not. Verify that
the credentials are different.
See NB#183566, NB#187583
"""
def do_it():
"""
A little helper to keep the logic flowing. Does the actual
work of getting credentials for invoker and app
"""
# launch an application, leave invoker running
print "launching application"
invoker = Popen(['invoker', '--type=m', '--wait-term',
'fala_ft_hello.launch'], shell = False,
stdout = DEV_NULL, stderr = DEV_NULL)
# get pid of invoker
invoker_pid = invoker.pid
print "invoker pid = %s" % invoker_pid
# get credentials
invoker_creds = get_creds(pid = invoker_pid)
app_creds = get_creds(path = 'fala_ft_hello')
self.assert_(invoker_creds != None,
"error retrieving creds for invoker")
self.assert_(app_creds != None,
"error retrieving creds for fala_ft_hello")
invoker_creds.sort()
app_creds.sort()
print "invoker creds = %s" % invoker_creds
print "app creds = %s" % app_creds
kill_process('fala_ft_hello')
return (invoker_creds, app_creds)
# creds when applauncherd is running
creds1 = do_it()
# stop applauncherd
Popen(['initctl', 'stop', 'xsession/applauncherd']).wait()
time.sleep(2)
# remove sockets
try:
for f in glob.glob('/tmp/boost*'):
os.remove(f)
except Exception as e:
print e
# creds when applauncherd *is not* running
creds2 = do_it()
# start applauncherd
Popen(['initctl', 'start', 'xsession/applauncherd']).wait()
time.sleep(2)
# app shouldn't have the same credentials as invoker, when
# applauncherd *is* running
self.assert_(creds1[0] != creds1[1],
'app creds are the same as invoker creds')
# and the same when applauncherd is not running
# note that the invoker doesn't show up in e.g. "ps ax"
# because of its execing so we'll just use the creds from the
# first step as they should be the same
self.assert_(creds1[0] != creds2[1],
'app creds are the same as invoker creds when ' +
'applauncherd is not running')
def test_022(self):
"""
Launch an application as user and root both when applauncherd
is running and when it isn't. Compare the credentials between
the two cases and verify that they are the same.
See NB#183566, NB#187583
"""
# stop applauncherd
Popen(['initctl', 'stop', 'xsession/applauncherd']).wait()
time.sleep(2)
# remove sockets
try:
for f in glob.glob('/tmp/boost*'):
os.remove(f)
except Exception as e:
print e
def do_it():
"""
A helper function to launch application and get credentials
as user and root.
"""
handle = Popen(['su', '-', 'user', '-c',
'/usr/bin/fala_ft_hello'],
stdout = DEV_NULL, stderr = DEV_NULL)
# give the application some time to launch up
time.sleep(2)
user = get_creds('fala_ft_hello')
kill_process('fala_ft_hello')
root = launch_and_get_creds('/usr/bin/fala_ft_hello').sort()
return (user, root)
# get creds for a launched application when applauncherd
# is not running
creds1 = do_it()
# start applauncherd
Popen(['initctl', 'start', 'xsession/applauncherd']).wait()
time.sleep(2)
# get creds for the same application when applauncherd
# is running
creds2 = do_it()
# creds should be the same, regardless of applauncherd status
self.assert_(creds1[0] == creds2[0], 'creds for user-case different')
self.assert_(creds1[1] == creds2[1], 'creds for root-case different')
# creds should be different, when run as user and when run as root,
# regarless of applauncherd status
self.assert_(creds1[0] != creds1[1],
'creds are same when applauncherd is not running')
self.assert_(creds2[0] != creds2[1],
'creds are same when applauncherd is running')
# main
if __name__ == '__main__':
# When run with testrunner, for some reason the PATH doesn't include
# the tools/bin directory
if os.getenv('_SBOX_DIR') != None:
os.environ['PATH'] = os.getenv('PATH') + ":" + os.getenv('_SBOX_DIR') + '/tools/bin'
using_scratchbox = True
check_prerequisites()
start_launcher_daemon()
tests = sys.argv[1:]
mysuite = unittest.TestSuite(map(launcher_tests, tests))
result = unittest.TextTestRunner(verbosity=2).run(mysuite)
if not result.wasSuccessful():
sys.exit(1)
sys.exit(0)