#!/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 functionalities of invoker Authors: nimika.1.keshri@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 class InvokerTests(CustomTestCase): def setUp(self): debug("setUp") if daemons_running(): stop_daemons() self.START_DAEMONS_AT_TEARDOWN = True else: self.START_DAEMONS_AT_TEARDOWN = False if get_pid('applauncherd') == None: start_applauncherd() def tearDown(self): debug("tearDown") if get_pid('applauncherd') == None: start_applauncherd() wait_for_single_applauncherd() if self.START_DAEMONS_AT_TEARDOWN: start_daemons() def sighup_applauncherd(self): same_pid, booster_status = send_sighup_to_applauncherd() self.assert_(same_pid, "Applauncherd has new pid after SIGHUP") self.assert_(booster_status, "Atleast one of the boosters is not restarted") #Testcases def test_wait_term_m(self, sighup = True): self._test_wait_term('/usr/bin/fala_ft_hello', 'fala_ft_hello', 'm') if(sighup): self.sighup_applauncherd() self.test_wait_term_m(False) def test_wait_term_qml(self, sighup = True): self._test_wait_term('/usr/bin/fala_qml_helloworld', 'fala_qml_helloworld', 'd') if(sighup): self.sighup_applauncherd() self.test_wait_term_qml(False) def test_wait_term_e(self, sighup = True): self._test_wait_term('/usr/bin/fala_ft_hello', 'fala_ft_hello', 'e') if(sighup): self.sighup_applauncherd() self.test_wait_term_e(False) def _test_wait_term(self, app_path, app_name, btype, directlyKillInvoker=True): """ When calling invoker with --wait-term and killing invoker, the launched application should die too. """ kill_process(app_name) # Launch the app with invoker using --wait-term p = run_app_as_user_with_invoker(app_path,booster = btype, arg = '--wait-term' ) # Retrieve their pids app_pid = wait_for_app(app_name) # Make sure that both apps started self.assert_(app_pid != None, "%s not launched by invoker?" % app_path) # Send SIGTERM to invoker, the launched app should die if directlyKillInvoker : debug(" Send SIGTERM to invoker, the launched app should die") kill_process('invoker', None, 15) self.waitForAsertEqual(lambda: p.poll(), 143, "invoker was not killed.", timeout = 3) else : debug(" Send SIGTERM to shell which runs invoker, the launched app should die") kill_process(None, p.pid, 15) self.waitForAsertEqual(lambda: p.poll(), -15, "invoker was not killed.", timeout = 3) debug("Invoker return code: %s" %(p.poll())) self.waitForAsertEqual(lambda: get_pid(app_name), None, "Application '%s' was not killed!" % app_path, timeout = 8) def test_launch_wo_applauncherd(self): """ To Test that invoker can launch applications when the applauncherd is not running. Try launching applications with all boosters """ stop_applauncherd() if get_pid(PREFERED_APP) != None: kill_process(PREFERED_APP) p = run_app_as_user_with_invoker(PREFERED_APP, booster = 'm') pid1 = wait_for_app(PREFERED_APP) self.assert_(pid1 != None, "Application was executed") kill_process(PREFERED_APP) p = run_app_as_user_with_invoker(PREFERED_APP, booster = 'e') pid1 = wait_for_app(PREFERED_APP) self.assert_(pid1 != None, "Application was executed") kill_process(PREFERED_APP) p = run_app_as_user_with_invoker(PREFERED_APP, booster = 'q') pid1 = wait_for_app(PREFERED_APP) self.assert_(pid1 != None, "Application was executed") kill_process(PREFERED_APP) p = run_app_as_user_with_invoker(PREFERED_APP, booster = 'd') pid1 = wait_for_app(PREFERED_APP) self.assert_(pid1 != None, "Application was executed") kill_process(PREFERED_APP) start_applauncherd() def test_signal_forwarding(self, sighup = True): """ To test that invoker is killed by the same signal as the application """ #Test for m-booster debug("Test for m-booster") st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/signal-forward/fala_sf_m.py") debug("The Invoker killed by : <%s>" %op.split ('\n')[-1]) self.assert_(op.split('\n')[-1].find('Segmentation fault') != -1, "The invoker(m-booster) was not killed by the same signal") #Test for d-booster debug("Test for d-booster") st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/signal-forward/fala_sf_d.py") debug("The Invoker killed by : %s" % op.split('\n')[-1]) self.assert_(op.split('\n')[-1].startswith('Terminated') == True, "The invoker(d-booster) was not killed by the same signal") #Test for e-booster debug("Test for e-booster") st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/signal-forward/fala_sf_e.py") debug("The Invoker killed by : %s" % op.split('\n')[-1]) self.assert_(op.split('\n')[-1].startswith('Terminated') == True, "The invoker(e-booster) was not killed by the same signal") #This case is launching the application in user mode #Test for q-booster debug("Test for q-booster") st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/signal-forward/fala_sf_qt.py") debug("The Invoker killed by : %s" %op.split('\n')[-1]) self.assert_(op.split('\n')[-1].startswith('Aborted') == True, "The invoker(q-booster) was not killed by the same signal") if(sighup): self.sighup_applauncherd() self.test_signal_forwarding(False) def test_invoker_delay(self, sighup = True): """ Test the --delay parameter of the invoker. """ invokerDelay = 10 # launch an app with invoker --delay n debug("launching fala_ft_hello ...") p = Popen(['/usr/bin/invoker', '--delay', str(invokerDelay), '--type=m', '--no-wait', '/usr/bin/fala_ft_hello'], shell=False, stdout=DEV_NULL, stderr=DEV_NULL, preexec_fn=permit_sigpipe) pStartTime = time.time() appPid = wait_for_app('fala_ft_hello', timeout=7) try: falaStartTime = time.time() # wait a little debug("Waiting for invoker to terminate after %.1fs..." %(invokerDelay)) # time out loop, if invoker runs longer then invokerDelay + 1 this means that something is wrong while time.time() invokerDelay - 1, "invoker has terminated to soon: %.1fs (%.1fs was expected)" %(endTime - pStartTime, invokerDelay)) self.assertEqual(get_pid('fala_ft_hello'), appPid, "Test application shouldn't be killed.") finally: kill_process('fala_ft_hello') debug("Ok.") if(sighup): self.sighup_applauncherd() self.test_invoker_delay(False) def test_invoker_exit_status(self, sighup = True): """ To test that invoker returns the same exit status as the application """ #Run application without invoker and get the exit status debug("Run application without invoker and get the exit status") st, op = commands.getstatusoutput('/usr/bin/fala_status') app_st_wo_inv = os.WEXITSTATUS(st) debug("The exit status of app without invoker is : %d" %app_st_wo_inv) #Run application with invoker and get the exit status - booster-m case debug("Run application with invoker and get the exit status") st, op = commands.getstatusoutput('invoker --type=m --wait-term /usr/bin/fala_status') app_st_w_inv = os.WEXITSTATUS(st) debug("The exit status of app with invoker (booster-m) is : %d" %app_st_w_inv) #Run application with invoker and get the exit status - booster-e case debug("Run application with invoker and get the exit status") st, op = commands.getstatusoutput('invoker --type=e --wait-term /usr/bin/fala_status') app_st_we_inv = os.WEXITSTATUS(st) debug("The exit status of app with invoker (booster-e) is : %d" %app_st_we_inv) self.assert_(app_st_wo_inv == app_st_w_inv, "The invoker returns a wrong exit status for booster-m") self.assert_(app_st_wo_inv == app_st_we_inv, "The invoker returns a wrong exit status for booster-e") if(sighup): self.sighup_applauncherd() self.test_invoker_exit_status(False) def test_invoker_search_prog(self, sighup = True): """ Test that invoker can find programs from directories listed in PATH environment variable and that it doesn't find something that isn't there. """ # invoker searches PATH for the executable p = run_app_as_user_with_invoker(PREFERED_APP, booster = 'm', arg = '--no-wait') try: self.waitForAsertEqual(lambda: p.poll(), 0, "Couldn't launch fala_ft_hello") finally: wait_for_app('fala_ft_hello') kill_process('fala_ft_hello') # launch with relative path p = run_cmd_as_user('cd /usr/share/; invoker --type=m --no-wait ' + "../bin/fala_ft_hello") try: self.waitForAsertEqual(lambda: p.poll(), 0, "Couldn't launch fala_ft_hello" + " with relative path or invoker didn't terminate") finally: wait_for_app('fala_ft_hello') kill_process('fala_ft_hello') # and finally, try to launch something that doesn't exist p = run_cmd_as_user('invoker --type=m --no-wait spam_cake') try : self.waitForAsertEqual(lambda: p.poll(), 1, "spam_cake has been found!") finally: kill_process('spam_cake') if(sighup): self.sighup_applauncherd() self.test_invoker_search_prog(False) def test_invoker_gid_uid(self, sighup = True): """ To Test that the set gid and uid is passed from invoker process to launcher """ debug("This test uses a test application that returns the uid and gid and exits") #get the id in user mode debug("Get the system's uid and gid 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] debug("System %s \tSyetem %s" %(usr_id1, grp_id1)) #get invokers's uid and gid by running the application using invoker in user mode debug("get invoker's uid and gid by running the application using invoker in user mode") app = "invoker --type=m --no-wait /usr/bin/fala_status" st, op = commands.getstatusoutput('su user -c "%s"' %app ); usr_id = op.split('\n')[1] grp_id = op.split('\n')[2] debug("Invoker %s \tInvoker %s" %(usr_id, grp_id)) #get application's uid and gid by running the application without invoker in user mode debug("get application's uid and gid by running the application without invoker in user mode") app = "/usr/bin/fala_status" st, op = commands.getstatusoutput('su user -c "%s"' %app ); usr_id2 = op.split('\n')[-2] grp_id2 = op.split('\n')[-1] debug("Application %s \tApplication %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 debug("Get the Sysem's uid and gid in Root Mode \n") st, op = commands.getstatusoutput("id") usr_id1 = op.split(' ')[0].split('(')[0] grp_id1 = op.split(' ')[1].split('(')[0] debug("System %s \tSyetem %s" %(usr_id1, grp_id1)) #get id by running the application using invoker in root mode debug("get invoker's uid and gid by running the application using invoker in root mode") app = "invoker --type=m --no-wait /usr/bin/fala_status" st, op = commands.getstatusoutput("%s" %app ); usr_id = op.split('\n')[1] grp_id = op.split('\n')[2] debug("Invoker %s \tInvoker %s" %(usr_id, grp_id)) #get id by running the application without invoker in root mode debug("get application's uid and gid by running the application without invoker in root mode") app = "/usr/bin/fala_status" st, op = commands.getstatusoutput("%s" %app ); usr_id2 = op.split('\n')[-2] grp_id2 = op.split('\n')[-1] debug("Application %s \tApplication %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") if(sighup): self.sighup_applauncherd() self.test_invoker_gid_uid(False) def test_invoker_param_creds(self): p = run_cmd_as_user('invoker --creds') self.assert_(p.wait() == 0, "'invoker --creds' failed") def test_invoker_param_respawn_delay(self, sighup = True): p = run_cmd_as_user('invoker --respawn 10 --type=q --no-wait fala_ft_hello') try : startTime = time.time() wait_for_app('fala_ft_hello') pid = wait_for_app('booster-q', timeout = startTime - time.time() + 12) endTime = time.time() self.assert_(endTime-startTime>8, "'booster-q' was respawned too soon: %.1fs" %(endTime-startTime)) self.assert_(pid != None, "'booster-q' was not respawned on time.") p = run_cmd_as_user('invoker --respawn 256 --type=q --no-wait fala_ft_hello') self.assert_(p.wait() != 0, "invoker didn't die with too big respawn delay") finally: kill_process('fala_ft_hello') if(sighup): self.sighup_applauncherd() self.test_invoker_param_respawn_delay(False) def test_invoker_bogus_apptype(self): p = run_cmd_as_user('invoker --type=foobar fala_ft_hello') self.assert_(p.wait() != 0, "invoker didn't die with bogus apptype") p = run_cmd_as_user('invoker fala_ft_hello') self.assert_(p.wait() != 0, "invoker didn't die with empty apptype") def test_invoker_signal_forward(self, sighup = True): """ Test that UNIX signals are forwarded from invoker to the invoked process """ st, op = commands.getstatusoutput("/usr/share/applauncherd-testscripts/signal-forward/fala_inv_sf.py") debug("The Invoker killed by : <%s>" %op) self.assert_(op.startswith('Segmentation fault') == True, "The invoker(m-booster) was not killed by the same signal") if(sighup): self.sighup_applauncherd() self.test_invoker_signal_forward(False) def test_wrong_type(self): """ Test that invoker help is printed if application is invoked using a wrong type """ cmd = '/usr/bin/invoker --type=f /usr/bin/fala_wl' debug("Launch application with wrong type %s" %cmd) st, op = commands.getstatusoutput('su - user -c "%s"' %cmd) self.assert_(op.split("\n")[0] == 'invoker: error: Unknown application type: f ',"No Error displayed") self.assert_(op.split("\n")[2] == 'Usage: invoker [options] [--type=TYPE] [file] [args]',"No usgae displayed") def test_unknown_parameter(self): """ Test that help is printed if unknown parameter is passed to invoker """ cmd = '/usr/bin/invoker --type=m --x /usr/bin/fala_wl' debug("Launch application with wrong option %s" %cmd) st, op = commands.getstatusoutput('su - user -c "%s"' %cmd) self.assert_(op.split("\n")[2] == 'Usage: invoker [options] [--type=TYPE] [file] [args]',"No usage displayed") def test_non_existing_binary_launch(self): """ Test that invoker gives error when it tries to launch a binary that does not exist """ cmd = '/usr/bin/invoker --type=m /usr/bin/fala_foo' debug("Launch a non existing application %s" %cmd) st, op = commands.getstatusoutput('su - user -c "%s"' %cmd) self.assert_(st != 0,"The application was launched") def test_invoker_symlink(self): """ Test that the symlink of invoker is unable to launch applications """ os.system("ln -s /usr/bin/invoker /usr/bin/invoker_link") cmd = "/usr/bin/invoker_link --type=m /usr/bin/fala_wl" st, op = commands.getstatusoutput('su - user -c "%s"' %cmd) os.system("rm /usr/bin/invoker_link") self.assert_(st != 0,"The application was launched") def test_invoker_usage_printing(self): """ Test that applauncherd invoker --help usage printing ok """ p = run_cmd_as_user('invoker --help') self.assert_(p.wait() == 0, "'invoker --help' failed") def test_invoker_help_printing(self): """ Test that applauncherd invoker usage printing ok """ p = run_cmd_as_user('invoker') self.assert_(p.wait() == 1, "'invoker' failed") def test_app_link(self, sighup = True): """ Test that symlink of an application can be launched. """ os.system("ln -s /usr/bin/fala_wl /usr/bin/fala_link") cmd = "/usr/bin/invoker --type=m /usr/bin/fala_link" os.system('su - user -c "%s"&' %cmd) pid = wait_for_app("fala_link") os.system("rm /usr/bin/fala_link") kill_process("fala_link") self.assert_(pid != None ,"The application was not launched") if(sighup): self.sighup_applauncherd() self.test_app_link(False) def test_D_and_G_option(self, sighup = True): """ Test that -D and -G options work and applications are launcherd -G = INVOKER_MSG_MAGIC_OPTION_DLOPEN_GLOBAL -D = INVOKER_MSG_MAGIC_OPTION_DLOPEN_DEEP """ p = run_app_as_user_with_invoker("/usr/bin/fala_wl", booster='m', arg = '-G') wait_for_app('fala_wl') returnCode = p.poll() kill_process("fala_wl") p.wait() self.assert_(returnCode == None ,"The application was not launched") p = run_app_as_user_with_invoker("/usr/bin/fala_wl", booster='m', arg = '-D') wait_for_app('fala_wl') returnCode = p.poll() kill_process("fala_wl") p.wait() self.assert_(returnCode == None ,"The application was not launched") if(sighup): self.sighup_applauncherd() self.test_D_and_G_option(False) def test_app_directory(self, sighup = True): """ Test that invoker is unable to launch a application which is a directory """ #Test for a directory os.system("mkdir /usr/bin/fala_dir") st, op = commands.getstatusoutput("/usr/bin/invoker --type=m /usr/bin/fala_dir") os.system("rm -rf /usr/bin/fala_dir") self.assert_(st != 0 ,"The application was not launched") if(sighup): self.sighup_applauncherd() self.test_app_directory(False) def test_unsetPATH_launch(self): """ Unset the PATH env variable and try to launch an application with relative path. The launch should fail """ st, op = commands.getstatusoutput("(unset PATH;/usr/bin/invoker --type=m fala_wl)") self.assert_(st != 0, "The application was launched") self.assert_(op == "invoker: died: could not get PATH environment variable", "The application was launched") def test_invoker_wait_term(self, sighup = True): """ start application with --wait-term parameter. Check that application is started and invoker is waiting termination before exit """ kill_process('fala_wait') # launch an app with invoker --wait-term debug("launching fala_wait ...") p = Popen(['/usr/bin/invoker', '--type=m', '--wait-term', '/usr/bin/fala_wait'], shell=False, stdout=DEV_NULL, stderr=DEV_NULL, preexec_fn=permit_sigpipe) # wait a little debug("waiting ...") wait_for_app('fala_wait', sleep = 0.3) # fala_wait is quits after 6 seconds endTime = time.time() + 6 success = True while time.time()