P[c@sddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z yddl m Z e Wn!ek rddlm Z nXddlmZddlZddlmZddlZddlZddlZddlZejjejZdejjfdYZdejfdYZ ej!dS( iN(tStringIO(tBytesIO(t_tTestSuiteUserInterfacecBseZdZdZdZeddZdZdZ dZ dZ dZ d Z d Zd Zd Zd ZdZdZRS(s?Concrete apport.ui.UserInterface suitable for automatic testingcCstj|_|jjd|jj|jjtjdd9Z?d:Z@d;ZAd<ZBd=ZCd>ZDd?ZEd@ZFdAZGdBZHdCZIdDZJdEZKdFZLdGZMdHZNdIZOdJZPdKZQdLZRRS(NcCsx<ddddgD](}ytj|=Wqtk r:qXqWtjj|_tjtj_tj j |_ tjtj _ tj j |_tj\}tj _ tj|tj|_dgt_t|_ tj|_ d|j dsTdef add_info(report, ui): report['CrashDB'] = "{ 'impl': 'memory', 'local_opt'" s package hooks@def add_info(report, ui): report['CrashDB'] = 'nonexisting' s|def add_info(report, ui): report['CrashDB'] = """{'impl': 'memory', 'trap': exec('open("/tmp/pwned", "w").close()')}""" s /tmp/pwned(RRRRRkR RRfRR^RRRRtassertInRR(R'R|((s&/usr/share/apport/testsuite/test_ui.pyt test_collect_info_crashdb_errorss@$   $   $   $   cCs[|jj|jj|j|jjt|j|jjd|j|jj dd}||j d<|j |jj|jj|j|jjt |j|jj d|j|jj |d|j_ d}d|j d<|j |jj|jj|j|jjt |j|jj d|j|jj ddS(shandle_duplicate()shttp://example.com/1t _KnownReportR0RTN(RRRiR Rwthandle_duplicateRR(RR$R^RjR,R*(R'tdemo_url((s&/usr/share/apport/testsuite/test_ui.pyttest_handle_duplicates&     cCs2gt_t|_|j|jjtdS(s0running the frontend without any pending reportsN(RcRdRRRwtrun_argvR(R'((s&/usr/share/apport/testsuite/test_ui.pyttest_run_nopendings  cCs|j}tjjtjjd}t|d}|j|WdQXgt _ t |_ it d6t d6t d6t d6|j _|j j|j|j jtdS(s8running the frontend with pending reports offers restarts test.crashtwbNR^t blacklisttexamineR(t_gen_test_crashRRRRRXRYRR RcRdRRRR RRwt offer_restartR,(R'RRiR|((s&/usr/share/apport/testsuite/test_ui.pyttest_run_restarts     cCsNddgt_t|_|j|jjt|j|jjddS(s-run_report_bug() without specifying argumentssui-tests-fR4N(RcRdRRRwRRR*(R'((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_noargss cCsddgt_t|_tj}tt_|j|jjttjj }|t_|j|t jj ddS(s6run_report_bug() as "ubuntu-bug" with version arguments ubuntu-bugs-vs N( RcRdRRtstdoutRRwRR,tgetvalueRt __version__(R't orig_stdouttoutput((s&/usr/share/apport/testsuite/test_ui.pyttest_run_versions    cCsddddgt_t|_itd6td6td6td6|j_|j|jjt|j|jj d|j|jj d|j |jj |j|jjd |jjj|j |jjd k|j|jjd d|j d |jjjk|j d |jjjk|j|jjddddddgt_t|_y|jjWntk rnX|j|jj ddS(srun_report_bug() for a packagesui-tests-fs-pRR^RRRshttp://bash.bugs.example.com/%iiRPRt ProcEnvironRRtnonexisting_gibberishR4N(RcRdRRR,RR RwRR*RR(RR%R$Rt latest_idRR^Rt SystemExit(R'((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_package s.  &  cCstj}|dkrhtjtjdtjtjjtjddgt sht dnt j dzrddd d d t |gt_t|_itd 6t d 6t d6t d6|j_|j|jjtWdtj|tjtj|dX|jd|jjjk|jd|jjjk|jd|jjjk|j|jjdd|jd|jjk|jd|jjjk|j|jjdd|jd|jjjk|jd |jjdk|j|jjd|j|jjd|j|jj d|jj!j"|j|jj#|j|jj$dkdS(s*run_report_bug() for a pid with extra tagsis /dev/nulls /usr/bin/yestyessCould not execute /usr/bin/yesg?sui-tests-fs--tagROs-PR^RRRNRPRtProcMapsRMRRRRtTagss$http://coreutils.bugs.example.com/%i(%Rtforktdup2RtO_WRONLYRcRtfilenotexecvRR7RRtstrRdRRR,R RwRtkilltsignaltSIGKILLtwaitpidRR^RRR*RR(R$RRR%R(R'tpid((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_pid_tags,s<  ( !  &cCsad}xTtr\|d7}ytj|dWq tk rX}|jtjkrYPqYq Xq W|S(sFind and return an unused PIDii(R,RRR{terrnotESRCH(tklassRte((s&/usr/share/apport/testsuite/test_ui.pyt_find_unused_pidVs   cCsD|j}dddt|gt_t|_|jjdS(s&run_report_bug() for a nonexisting pidsui-tests-fs-PN(RRRcRdRRR(R'R((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_wrong_pidds  cCst}tjdkr4tjdddt}nzHddddgt_t|_|jj |j |jj dWd |rtjdddnXd S( s9run_report_bug() for a pid which runs as a different useriiisui-tests-fs-PRTR4N( RRtgetuidt setresuidR,RcRdRRRRwR*(R't restore_root((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_noperm_pidns   cCs<tj\}}tdd}tj||jWdQXtj|tj|dtj}|dkrtj tjdtj t j j tj||gnzAddd t|gt _t|_|jt|jjWdtj|tjtjtj|X|j|jjd dS( s3run_report_bug() for a pid of an unpackaged programs /usr/bin/yestrbNiis /dev/nullsui-tests-fs-PR4(RRaRRR treadRbtchmodRRRRcRRRRRdRRt assertRaisesRRRRRtwaitRvRwR*(R'RotexenameR|R((s&/usr/share/apport/testsuite/test_ui.pyt"test_run_report_bug_unpackaged_pids"   (  cCsd}xrtjdD]a}t|}|jj}WdQXt|d}|tjj@rt|d}PqqW|j |dkdddt |gt _ t |_itd6td 6td 6td 6|j_|jj|j|jjd jtjjdS( s-run_report_bug() for a pid of a kernel threads/proc/[0-9]*/statNiisui-tests-fs-PR^RRRRN(RRzRRtsplittintRRt PF_KTHREADRRRcRdRR,RR RRR^t startswitht packagingtget_kernel_package(R'RRR|Rtflags((s&/usr/share/apport/testsuite/test_ui.pyt!test_run_report_bug_kernel_threads"   cCstjjtjjd}tj|tjj|d}ddddd|gt_t |_ |j |j j t |j |j jd |j |j jd |j |j jd |j|j j|j|j jdktj}t|d }|j|Wd QX|j |d d|jd |jk|jd |jk|j |dddd|gt_t |_ it d6td6td6td6|j _|j |j j t |j |j jd |j |j jd |j|j jd S(s/run_report_bug() with saving report into a filethomesbashisbad.apportsui-tests-fs-pRs--saveiRNRPRRRRs-cR^RRR(RRRRRXRYtmkdirRcRdRRRwRR,R*RR(R$RR%RRRfRtloadRRR R)(R'tdt reportfileRR|((s&/usr/share/apport/testsuite/test_ui.pyttest_run_report_bug_files8     cCsd}tj|tjs+t|dtj}|dkrtjtjdtjtj j tj j tj tjtjd tjtjjtj||gtstd|ntjdtj}||dEscSs0d|dreport['begin'] = '1' raise StopIteration report['end'] = '1' N(RRR(R'((s&/usr/share/apport/testsuite/test_ui.pyttest_interactive_hooks_cancelscCsKdddgt_t|_itd6td6td6td6|j_|j|jjt|j d|jj k|j|jj d t t jjtjjd d }|jd |jtj}ddd gt_t|_tt_|jt|jjtjj}|t_|j d|kt t jjtjjdd }|jd|jdddgt_t|_tt_|jt|jjtjj}|t_|j d|kt t jjtjjdd }|jd|jdddgt_t|_tt_|jt|jjtjj}|t_|j d|k|j d|kt t jjtjjdd }|jd|jdddgt_t|_itd6td6td6td6|j_|j|jjt|j|jj d,|j|jj d,|j |jj|j|jjdd|j d|jjk|j|jjdd|j |jjd jd!|j|jjd"d#dd$d%ddgt_t|_itd6td6td6td6|j_|j|jjt|j|jj d,|j|jj d,|j |jj|j|jjdd|j d%|jjd&kt t jjtjjdd }|jd'|jdddgt_t|_itd6td6td6td6|j_t|j_|j|jjt|j |jj|j|jj d(|j|jjdd)|j d|jjk|j|jjdd|j |jjd jd!|j|jjd"d#|j|jjd*d+d,S(-s run_symptom()sui-tests-stfoobarR^RRRsfoobar" is not knownR4snopkg.pyRsdef run(report, ui): pass tnopkgs&did not determine the affected packagesnorun.pys"def something(x, y): return 1 tnorunsnorun.py crashed:scrash.pys$def run(report, ui): return 1/0 tcrashscrash.py crashed:sZeroDivisionError:s itching.pysBdef run(report, ui): report["itch"] = "scratch" return "bash" titchingtitchtscratchRRPRRNsbash RRs--tagRORsndef run(report, ui): report['itch'] = 'slap' report['q'] = str(ui.yesno('do you?')) return 'bash' sdo you?tslaptqR,N(RcRdRRR,RR RwRRR)R*RRRRRR\R RbtstderrRRRRRR%R^RR!(R'R|t orig_stderrterr((s&/usr/share/apport/testsuite/test_ui.pyttest_run_symptoms  $      $     $     $       $     cCsttjjtjjdd}|jd|jttjjtjjdd}|jd|jddgt _ t |_it d6t d 6t d 6t d 6|j_d|j_|j|jjt |j|jjd|jd |jjk|jt|jjtd ddg|j|jjd|j|jjd|j|jj|jjjdg|j_|j|jjt |j|jjd|j|jjdk|j|jj|j|jjdjddS(sDrun_report_bug() without specifying arguments and available symptomssfoo.pyRsIdescription = 'foo does not work' def run(report, ui): return 'bash' sbar.pys*def run(report, ui): return "coreutils" sui-tests-fR^RRRskind of problemRsfoo does not works Other problemiRNRN(RRRRRRR\R RbRcRdRR,RR RR"RwRR*RR)RR+RR^RR%tindexR(R'R|((s&/usr/share/apport/testsuite/test_ui.pyt!test_run_report_bug_list_symptomss8$ $     csfd}|ddi td6dd6dd6dd6dd6dd6dd 6td 6gd 6td 6jt|d di|ddi td6dd6dd6dd6dd6dd6dd 6td 6gd 6td 6ttjjt j j dd}|j d|j |ddi td6dd6dd6dd6dd6dd6dd 6td 6gd 6td 6|ddi td6dd6dd6dd6dd6dd6dd 6td 6gd 6td 6xldD]d}|dd|i td6dd6dd6d|d6dd6dd6dd 6td 6gd 6td 6qW|ddi td6dd6dd6dd6dd6dd6dd 6td 6gd 6td 6|d ditd6dd6dd6dd6dd6gd 6|dditd6dd6dd6dd6dd6gd 6dS(s3parse_args() option inference for a single argumentcs|gt_|r%tjj|ntj}tddt_ztjj}Wdtjj|t_Xd|d<j |j gj |j |dS(Ns /dev/nullRtversion( RcRdtappendRRRRRRbRRwtargsRA(t program_nametargt expected_optsRR(R'(s&/usr/share/apport/testsuite/test_ui.pyt_chks     s apport-gtktfilebugRRt crash_filetsymptomt update_reporttsavetwindowttagthangingsapport-collects apport-kdeRs coreutils.pyRsEdescription = 'foo does not work' def run(report, ui): return 'bash' s apport-clit1234s.crashs.apports /tmp/f oos /usr/bin/tailisapport-update-bugN(s.crashs.apport(RRRRR,RRRRRRR\R Rb(R'RR|R-((R's&/usr/share/apport/testsuite/test_ui.pyttest_parse_argv_single_argsN   $     csfd}|gi td6dd6dd6dd6dd6dd6dd6td 6gd 6td 6|d gi td6d d6dd6dd6dd6dd6dd6td 6gd 6td 6ttjjtjj d d}|j d|j |d gi td6dd6dd6dd6d d6dd6dd6td 6gd 6td 6tj tjjtjj d |dgi td6dd6dd6dd6dd6dd6dd6td 6gd 6td 6xldD]d}|d|gi td6dd6dd6d|d6dd6dd6dd6td 6gd 6td 6qW|dgi td6d d6dd6dd6dd6dd6dd6td 6gd 6td 6|ddd gi td6d d6dd6dd6dd6dd6dd6td 6gd 6td 6|ddd gi td6d d6dd6dd6dd6dd6dd6td 6dgd 6td 6|ddddd gi td6d d6dd6dd6dd6dd6dd6td 6ddgd 6td 6j t|ddddgidS(s3parse_args() option inference when invoked as *-bugcsdg|t_tj}tddt_ztjj}Wdtjj|t_Xd|d<j |j gj |j |dS(Ns apport-bugs /dev/nullRR( RcRdRRRRRRbRRwRRA(RRRR(R'(s&/usr/share/apport/testsuite/test_ui.pyRs    RRRRRRRRRRRs coreutils.pyRsEdescription = 'foo does not work' def run(report, ui): return 'bash' Rs.crashs.apports /tmp/f oos /usr/bin/tails--saves foo.apports--tagRORs-cs/tmp/foo.reports-uN(s.crashs.apport(R,RRRRRRRRR\R RbRvRR(R'RR|R-((R's&/usr/share/apport/testsuite/test_ui.pyttest_parse_argv_apport_bugsZ$ !"!   $   # cCs~|jj|jjtjd}|jj}z.d|j_dtjd<|j|jjt tj j tj j tj j tj j td}tjtj j |dtjr|tjd<|j|jjtn"|j|jjt tgkd|j_|j|jjt ||j_|j|jjt Wd|tjd<||j_XdS(s(can_examine_locally() for a crash reporttPATHcSstS(N(R,(tcommand((s&/usr/share/apport/testsuite/test_ui.pyR\]sRtbinsapport-retracecSstS(N(R(R((s&/usr/share/apport/testsuite/test_ui.pyR\lsN(RRRiR RRtui_run_terminalRwtcan_examine_locallyRRRtdirnametrealpatht__file__R R R,R(R't orig_pathtorig_fnt src_bindir((s&/usr/share/apport/testsuite/test_ui.pyttest_can_examine_locally_crashUs&    0$ "  cCso|jj|jj|jjd=|jj}z,d|j_|j|jjtWd||j_XdS(s,can_examine_locally() for a non-crash reportRScSstS(N(R,(R((s&/usr/share/apport/testsuite/test_ui.pyR\sN( RRRiR R^RRwRR(R'R((s&/usr/share/apport/testsuite/test_ui.pyt test_can_examine_locally_nocrashws  cCs|jjj}ddddgt_t|_d|jj_itd6td6td6td 6|j_ |j |jj t|j |jj d|j |jjd|j|jj|j |jjd d|jd |jjjk|jd |jjjk|j |jjd d|j |jjd|j |jjd|j |jjj|dS(s%crash database does not accept reportsui-tests-fs-pRcSstS(N(R(R((s&/usr/share/apport/testsuite/test_ui.pyR\sR^RRRRPRRRRiN(RRRRcRdRtacceptsR,RR RwRR*RR(RR%R^RR$R(R'R~((s&/usr/share/apport/testsuite/test_ui.pyttest_db_no_accepts&  cCstj}|jd|j|j|jd<|j|j_|jj}tj j dkrld}ndj d}|j |idd6dd 6d d 6|d 6d d6dS(sparsing of .desktop filess[Desktop Entry] Name=gtranslate GenericName=Translator GenericName[de]=Übersetzer Exec=gedit %U Categories=GNOME;GTK;Utility;TextEditor; t DesktopFileis ÜbersetzersUTF-8t Translatort genericnamesGNOME;GTK;Utility;TextEditor;t categoriest gtranslateR sgenericname[de]sgedit %UtexecN( RR R R R R^Rtget_desktop_entryRct version_infotmajorR)Rw(R't desktop_fileR0texp_genericname((s&/usr/share/apport/testsuite/test_ui.pyttest_get_desktop_entrys   cCsEtj}|jd|j|j|jd<|j|j_|jj}tj j dkrld}ndj d}|j |idd6dd 6d d 6|d 6d d6dd6|j d|jdjd|j|j |jjd|j d|jdjd|j|j |jjddS(s parsing of broken .desktop filess[Desktop Entry] Name=gtranslate GenericName=Translator GenericName[de]=Übersetzer Exec=gedit %U Keywords=foo;bar; Categories=GNOME;GTK;Utility;TextEditor; Keywords=baz Ris ÜbersetzersUTF-8RRsGNOME;GTK;Utility;TextEditor;RRR sgenericname[de]tbaztkeywordssgedit %URis5Name=gtranslate GenericName=Translator Exec=gedit %U sE[Desktop Entry] Name gtranslate GenericName=Translator Exec=gedit %U N(RR R R R R^RRRcRRR)RwRqRSR(R'RR0R((s&/usr/share/apport/testsuite/test_ui.pyttest_get_desktop_entry_brokens4        cCstj}|dkrhtjtjdtjtjjtjddgt sht dnt j dtj |tjtj|d|jj|dS(Nis /dev/nulls /usr/bin/yesRsCould not execute /usr/bin/yesg?(RRRRRRcRRRRR7RRRRRRRt wait_for_pid(R'R((s&/usr/share/apport/testsuite/test_ui.pyttest_wait_for_pids  ( N(SRERFRpRjR}RRRRRRRRRRRRRRRRRRRt classmethodRRRRRRRR"R$R(R*R+R,R0R6R8R:R<R?RARCRERIRNRZRbRhRnRpRttunittesttskipIfRzRRRRRRRRRRRRRRRRRRRRRRRRR(((s&/usr/share/apport/testsuite/test_ui.pyRHs *     !     3     *    ( % E   +     &  !  *  4 6  / " ' " !2     #      r ( I Z " #  3("RRtRRRRTRRRcRxRRzt cStringIORt ImportErrortioRt apport.uiRRt apport.reportRgtapport.crashdb_impl.memoryRRftget_logind_sessiontgetpidRzRRRtTestCaseRHtmain(((s&/usr/share/apport/testsuite/test_ui.pyts2l$      j