~ea ddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddlm Z ddlm Z ddlm Z ddl mZddlmZddlmZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddl m!Z!Gdde j,Z"Gdde j,Z#GddZ$Gdde$Z%GddeZ&Gdde Z'Gdde(Z)Gdd Z*Gd!d"Z+Gd#d$Z,Gd%d&Z-Gd'd(Z.ddd)d*d*d*dddddgd+f d,Z/d9d-Z0d.Z1Gd/d0Z2Gd1d2Z3Gd3d4Z4Gd5d6Z5Gd7d8eZ6y):N)ERROR) Formatter)Handler)Deferred) ConnectError) StringType)Failure)TestCase)_PY3) ConfigParser) cstringio)stringio)BaseConfiguration)EventHandlingReactorMixin) LoginInfoc*eZdZes ej Zyy)CompatTestCaseN)__name__ __module__ __qualname__r r assertItemsEqualassertCountEqual7/usr/lib/python3/dist-packages/landscape/lib/testing.pyrrs #44 rrc,eZdZgZfdZfdZxZS)HelperTestCasec:t|g|_t|jvr |jj dtd}|jD]A}|}t |dr|j|}|jj|C|S)Nrset_up) supersetUp_helper_instancesLogKeeperHelperhelpersinserthasattrrappend)selfresulthelper_factoryhelper __class__s rr!zHelperTestCase.setUp's  !# $,, . LL  ? 3"ll 2N#%Fvx(t,  " " ) )& 1  2 rct|jD] }t|ds|j|"t|y)N tear_down)reversedr"r&r.r tearDown)r(r+r,s rr0zHelperTestCase.tearDown7sBt556 'Fv{+  & ' r)rrrr$r!r0 __classcell__r,s@rrr#sG rrcHeZdZdZ ddZdZ ddZd dZy) FSTestCasect|d5}|j}ddd|j|y#1swYxYw)Nrb)openread assertEqual)r(filenameexpected_contentfdactual_contents rassertFileContentzFSTestCase.assertFileContent@s? (D ! 'RWWYN ' )>: ' 's 9ANc |7|tj}tjj ||nHFtj |||\} tj | |tj|&t|5} | j|ddd|j|jrfd} |j| S#1swY@xYw)aCreate a temporary file and return the path to it. @param content: Initial content for the file. @param suffix: Suffix to be given to the file's basename. @param prefix: Prefix to be given to the file's basename. @param basename: Full basename for the file. @param dirname: Put file inside this directory. The file is removed after the test runs. NcV tjzy#t$rYywxYwN)osremoveOSError) backupsuffixpathsr remove_backupz*FSTestCase.makeFile..remove_backupjs+IId\12s  (() tempfilemkdtemprBrFjoinmkstempcloseunlinkr7write addCleanup _clean_file) r(contentsuffixprefixbasenamedirnamerFmoderEr<filerGs ` ` rmakeFilezFSTestCase.makeFileEs*  "**,77<<2D \''@HB HHRL $  dD! $T 7# $ (($/   OOM *  $ $s C##C,c tjj|rtj|ytj |y#t $rYywxYw)ztTry to remove a filesystem path, whether it's a directory or file. @param path: the path to remove N)rBrFisdirshutilrmtreerMrD)r(rFs rrPzFSTestCase._clean_filets@  ww}}T" d# $   s4A A AAc|tj|ntj|||}|j |j ||S)a@Create a temporary directory and return the path to it. @param suffix: Suffix to be given to the file's basename. @param prefix: Prefix to be given to the file's basename. @param dirname: Put directory inside this parent directory. The directory is removed after the test runs. )rBmakedirsrHrIrOrP)r(rRrSrUrFs rmakeDirzFSTestCase.makeDirsC   KK ##FFG\\^F ==&4=H 5!r)NtmpNNNwN)rfrgNNrA)rrrr>rXrPr_rerrrr4r4?sD;  -^   ,rr4c.eZdZfdZfdZdZxZS)ConfigTestCasect|tj|_|j dgt_yNrf)r r!rdefault_config_filenames_old_config_filenamesrXr(r,s rr!zConfigTestCase.setUps/  %6%O%O"6:mmB6G5H2rcL|jt_t|yrA)rnrrmr r0ros rr0zConfigTestCase.tearDowns595O5O2 rc t|}t}|j|t|}t}|j||jt |j t |j |j D]D}|jt |j|t |j|Fy)z Compare two configuration files for equality. The order of parameters and comments may be different but the actual parameters and sections must be the same. N)r r read_filer9setsectionsdictitems)r(firstsecondfirst_fp first_parser second_fp second_parsersections rassertConfigEqualz ConfigTestCase.assertConfigEquals U##~ x(f% $  *   %%' (  &&( ) $,,. G   \''01]((12  r)rrrr!r0r~r1r2s@rrjrjsI  rrjc,eZdZdZdZdZdZddZy)TwistedTestCasecg}|j|j|s|jd|dyt|dtr|jd|d|ddy|dS)zSee C{twisted.trial._synctest._Assertions.successResultOf}. This is a copy of the original method, which is available only since Twisted 12.3.0 (from 2012-12-20). zSuccess result expected on , found no result insteadrz, found failure result ( ) insteadNaddBothr'fail isinstancer r(deferredr)s rsuccessResultOfzTwistedTestCase.successResultOfs ' II-h\:** q 7 + II-h\:))/ Y@  !9 rcg}|j|j|s|jd|dyt|dts|jd|d|ddy|dS)zSee C{twisted.trial._synctest._Assertions.failureResultOf}. This is a copy of the original method, which is available only since Twisted 12.3.0 (from 2012-12-20). zFailure result expected on rrz, found success result (rNrrs rfailureResultOfzTwistedTestCase.failureResultOfs ' II-h\:** F1Iw/ II-h\:))/ Y@  !9 rczg}|j|j|r|jd|d|ddyy)zSee C{twisted.trial._synctest._Assertions.assertNoResult}. This is a copy of the original method, which is available only since Twisted 12.3.0 (from 2012-12-20). zNo result expected on z, found rz insteadN)rr'rrs rassertNoResultzTwistedTestCase.assertNoResultsK '  II( 5 X/  rc|jt|tgfd}|j||jy)Nc(jdyNT)r')r)calleds rcallbackz9TwistedTestCase.assertDeferredSucceeded..callbacks MM$ r) assertTruerr addCallback)r(rrrs @rassertDeferredSucceededz'TwistedTestCase.assertDeferredSucceededs<  8X67  X& rNcx|jt|t|j|j|S)zS Assert that the given C{deferred} results in the given C{result}. )rrrrr9rs r assertSuccesszTwistedTestCase.assertSuccess s0  8X67##D$4$4f==rrA)rrrrrrrrrrrrrs**  >rrceZdZdZdZy) ErrorHandlercDtj|g|i|g|_yrA)r__init__errors)r(argskwargss rrzErrorHandler.__init__s!/// rcb|jtk\r|jj|yyrA)levelnorrr')r(records remitzErrorHandler.emits% >>U " KK  v & #rN)rrrrrrrrrrs 'rrceZdZdZy)LoggedErrorsErrorctd}t}|jdD]}||j|dzz }|S)Nz!The following errors were logged r )rrformat)r(out formattererrors r__str__zLoggedErrorsError.__str__sD2K YYq\ 2E 9##E*T1 1C 2 rN)rrrrrrrrrsrrc"eZdZdZdZdZdZy)r#zRecord logging information. Puts a 'logfile' attribute on your test case, which is a StringIO containing all log output. cg|_g|_t|_||_t j x|_}t|_ t j|j}d}|jt j||j|_|j|_||jg|_ |j#t j$y)Nz%(levelname)8s: %(message)s)ignored_exception_regexesignored_exception_typesr error_handler log_helperlogging getLoggerloggerr logfile StreamHandler setFormatterrhandlers old_handlerslevel old_levelsetLevelNOTSET)r( test_caserhandlerrs rrzLogKeeperHelper.set_up+s)+&')$)^# $+$5$5$77 6%K '' (9(9:.W..v67"OO"D$6$67'rctj}|j|j|j|_g}|j jD]}|jD]:}|js|jds t|jd|s:K|jD]}|j|jsy|j||r t|yNr)rrrrrrrrrexc_info issubclassrmatchmessager'r)r(rrrr ignored_type ignored_regexs rr.zLogKeeperHelper.tear_down:s""$'++((// *F $ < < * OO*"6??1#5|D *&*%C%C*M$**6>>:*MM&) * #F+ + rct|tr/|jjt j |y|j j|yrA)rrrr'recompiler)r( type_or_regexs r ignore_errorszLogKeeperHelper.ignore_errorsPs= mZ 0  * * 1 1"**]2K L  ( ( / / >rN)rrr__doc__rr.rrrrr#r#$s (,,?rr#ceZdZdZdZy)EnvironSnapshotcJtjj|_yrA)rBenvironcopy _snapshotr(s rrzEnvironSnapshot.__init__Xs*rctjj|jt tjD]"}||jvstj|=$yrA)rBrupdaterlist)r(keys rrestorezEnvironSnapshot.restore[sG $..) # $C$..(JJsO $rN)rrrrrrrrrrWs +$rrceZdZdZdZy)EnvironSaverHelperc"t|_yrA)rrr(rs rrzEnvironSaverHelper.set_upcs (*rc8|jjyrA)rrrs rr.zEnvironSaverHelper.tear_downfs  rNrrrrr.rrrrrbs +!rrcBeZdZddZd dZd dZdZd dZedZ y) MockPopenNcj||_||_t||_g|_||_d|_yrA)outputerr_outr stdout popen_inputs return_codesreceived_input)r(rrrs rrzMockPopen.__init__ks4  ' ("rc,|j||||S)N)stdinrstderr)popenr(rrrrs r__call__zMockPopen.__call__sszz$eF6zJJrc<|jj||SrA)rr'rs rrzMockPopen.popenvs   & rc|jSrA) returncoders rwaitzMockPopen.waitzs rc@||_|j|jfSrA)rrr)r(inputs r communicatezMockPopen.communicate}s#{{DLL((rcR|jy|jjdSr)rpoprs rrzMockPopen.returncodes(    $  $$Q''rrl)NNNrA) rrrrrrrrpropertyrrrrrrjs0#K)((rrceZdZdZdZy)StandardIOHelperctj|_tj|_t x|_t_t x|_t_t sd|j_yy)NzUTF-8)sysr old_stdoutr old_stdinrr encodingrs rrzStandardIOHelper.set_upsO"zz !ii (0 2 3:&.j0 #)'.IOO $rcX|jt_|jt_yrA)rrrrrrs rr.zStandardIOHelper.tear_downs)) '' rNrrrrrrs /(rrz/dev/rf)rrrrc |t|d} | jtjtj |||j d|j d|j d|j d||| | | | d| d| d| dd| jy#| jwxYw) z3Append binary login data to the specified filename.abzutf-8rrN)r7rNstructpackr RAW_FORMATencoderL)r: login_typepid tty_deviceidusernamehostnametermination_status exit_status session_identry_time_secondsentry_time_millisecondsremote_ip_addressrWs rappend_login_datars $ D KK$$!!'* '"((""'!!$!!$!!$!!$#  ,  s B B))B;c# K ||dz } w)z>Generator starts at zero and yields integers that grow by one.rr)is r mock_counterrs  Q s ctdS)zCGenerator starts at 100 and yields int timestamps that grow by one.d)rrrr mock_timers  rc,eZdZdZdZdidddddfdZy)StubProcessFactoryzx A L{IReactorProcess} provider which records L{spawnProcess} calls and allows tests to get at the protocol. cg|_yrA)spawnsrs rrzStubProcessFactory.__init__s  rrNrc L|jj||||||||| f yrA)r!r') r(protocol executablerenvrFuidgidusePTYchildFDss r spawnProcesszStubProcessFactory.spawnProcesss6   r)rrrrrr*rrrrrs(      rrc"eZdZdZdZdZdZy) DummyProcessz/A process (transport) that doesn't do anything.cg|_yrA)signalsrs rrzDummyProcess.__init__s  rc:|jj|yrA)r.r')r(signals r signalProcesszDummyProcess.signalProcesss F#rcyrAr)r(r<s r closeChildFDzDummyProcess.closeChildFDs rN)rrrrrr1r3rrrr,r,s9$ rr,cJeZdZdZdZdZdZdZdZdZ dZ d Z d d Z d Z y )ProcessDataBuilderzBuilder creates sample data for the process info plugin to consume. @param sample_dir: The directory for sample data. z R (running)z T (stopped)zT (tracing stop)zD (disk sleep)z S (sleeping)zX (dead)z Z (zombie)c||_yrA) _sample_dir)r( sample_dirs rrzProcessDataBuilder.__init__ s %rNc Td|ddd|d|dd|dd| dd } tjj|jt |} tj | tjj| d } t | d } | j| | j|d |d}tjj| d } t | d } | j|| j|rdj|} nd} tjj| d} t | d } | j| | jy#| jwxYw#| jwxYw#| jwxYw)aCreates sample data for a process. @param started_after_boot: The amount of time, in jiffies, between the system uptime and start of the process. @param process_name: Used to generate the process name that appears in /proc/%(pid)s/status @param generate_cmd_line: If true, place the process_name in /proc/%(pid)s/cmdline, otherwise leave it empty (this simulates a kernel process) @param stat_data: Array of items to write to the /proc//stat file. z Name: Nz State: zE Tgid: 24759 Pid: 24759 PPid: 17238 TracerPid: 0 Uid: dz 0 0 0 Gid: zk 0 0 0 FDSize: 256 Groups: 4 20 24 25 29 30 44 46 106 110 112 1000 VmPeak: 11680 kB VmSize: a kB VmLck: 0 kB VmHWM: 6928 kB VmRSS: 6924 kB VmData: 1636 kB VmStk: 196 kB VmExe: 1332 kB VmLib: 4240 kB VmPTE: 20 kB Threads: 1 SigQ: 0/4294967295 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000000000 SigCgt: 0000000059816eff CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 statuszw+z*0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 statzA/usr/sbin/{process_name}--pid-file/var/run/{process_name}.pid ) process_namerfcmdline) rBrFrJr7strmkdirr7rNrLr)r( process_idstater&r'started_after_bootr>generate_cmd_line stat_datavmsize sample_data process_dirr:rWs r create_datazProcessDataBuilder.create_datas0 cr   Q Q  1: @ggll4#3#3S_E  77<< X6Hd#  JJ{ # JJL  ++=a*@I77<< V4Hd#  JJy ! JJL  F)   K77<< Y7Hd#  JJ{ # JJL7 JJL JJL JJLs$E+$F F+E=FF'ctjj|jt |}t j |y)z>Remove sample data for the process that matches C{process_id}.N)rBrFrJr7r@r[r\)r(rBrIs r remove_datazProcessDataBuilder.remove_datals,ggll4#3#3S_E  k"r)rNTNi-)rrrrRUNNINGSTOPPED TRACING_STOP DISK_SLEEPSLEEPINGDEADZOMBIErrJrLrrrr5r5sN GG%L!JH D F&[z#rr5ceZdZdZy) FakeReactorIDc d|_||_yr)active_data)r(datas rrzFakeReactorID.__init__ss  rN)rrrrrrrrUrUrsrrUceZdZdZiZfdZdZdZdZdZ fdZ dZ d Z d Z d Zd Zd ZdZdZdZdZdZdZxZS) FakeReactorawA fake reactor with the same API of L{LandscapeReactor}. This reactor emulates the asychronous interface of L{LandscapeReactor}, but implementing it in a synchronous way, for easier unit-testing. Note that the C{listen_unix} method is *not* emulated, but rather inherited blindly from L{UnixReactorMixin}, this means that there's no way to control it in a synchronous way (see the docstring of the mixin). A better approach would be to fake the AMP transport (i.e. fake the twisted abstractions around Unix sockets), and implement a fake version C{listen_unix}, but this hasn't been done yet. ctt|d|_g|_i|_g|_ddlm}||_y)Nr)reactor) r r _current_time_callshosts_threaded_callbackstwisted.internetr]_reactor)r(r]r,s rrzFakeReactor.__init__s8   #%  - rc,t|jSrA)floatr^rs rtimezFakeReactor.timesT''((rcd|j|z}||||f}|j|t|SrA)r^ _insort_callrU)r(secondsfrrscheduled_timecalls r call_laterzFakeReactor.call_laters9++g540 $T""rc|jDcgc]}|d }}tj||d}|jj||ycc}wr)r_bisect bisect_leftr%)r(rlctimesindexs rrhzFakeReactor._insort_callsN ${{+!1++""5$q'2 5$',s AcNfdjS)Ncjj_ iy#t$rjrj wxYwrA)rmrX ExceptionrW cancel_call)rrlrjfakerrir(srrxz$FakeReactor.call_every..fakesV$7==DJ 4"6" ;;$$T* s -(Arm)r(rirjrrrlrxs`````@@r call_everyzFakeReactor.call_everys$  w- rct|turE|j|jvr%|jj |jd|_yt ||yNF)typerUrXr_rCrWr rw)r(rr,s rrwzFakeReactor.cancel_callsI 8} $xx4;;& ""288,BI G  #rc(|jd|yrry)r(rjs rcall_when_runningzFakeReactor.call_when_runnings 1rcJ|jjfdy)z5Schedule a function for execution in the main thread.ciSrAr)rrjrsrz*FakeReactor.call_in_main..s40B60BrN)rar')r(rjrrs ```r call_in_mainzFakeReactor.call_in_mains   ''(BCrcN|j||||||jy)asEmulate L{LandscapeReactor.call_in_thread} without spawning threads. Note that running threaded callbacks here doesn't reflect reality, since they're usually run while the main reactor loop is active. At the same time, this is convenient as it means we don't need to run the the real Twisted reactor with to test actions performed on completion of specific events (e.g. L{MessageExchange.exchange} uses call_in_thread to run the HTTP request in a separate thread, because we use libcurl which is blocking). IOW, it's easier to test things synchronously. N) _in_thread_run_threaded_callbacks)r(rerrbackrjrrs rcall_in_threadzFakeReactor.call_in_threads$ '1dF; $$&rcLGfdd}|j<|S)NceZdZfdZy))FakeReactor.listen_unix..FakePortc<jjyrA) _socket_pathsr)oselfr( socket_paths r stopListeningz7FakeReactor.listen_unix..FakePort.stopListenings""&&{3rN)rrrr)r(rsrFakePortrs 4rr)r)r(rfactoryrs`` r listen_unixzFakeReactor.listen_unixs' 4 4+2;'zrc|jj|}ddlm}|r|||}|j |St }t td}|j|||S)Nr) FakeConnectorzNo such file or directory) rgetlandscape.lib.tests.test_amprconnectobjectr rclientConnectionFailed)r(rFrserverr connectorfailures r connect_unixzFakeReactor.connect_unixsm##''-> %gv6I     Il+FGHG  * *9g >rc|jdd|_|jr.|j|jdd|jr.|jdy)zAContinuously advance this reactor until reactor.stop() is called.runTrstopN)fire_runningadvancer_rs rrzFakeReactor.runsJ % mm LLQ* +mm &rcd|_yr|)rrs rrzFakeReactor.stops  rc|jr|jdd|j|zkr{|jjd}||d|jz z}|d|_ |d|di|d|jr#|jdd|j|zkr{|xj|z c_y#t$r}t j |Yd}~hd}~wwxYw)aHAdvance this reactor C{seconds} into the future. This method is not part of the L{LandscapeReactor} API and is specific to L{FakeReactor}. It's meant to be used only in unit tests for advancing time and triggering the relevant scheduled calls (see also C{call_later} and C{call_every}). rrrrN)r_r^rrvr exception)r(rirles rrzFakeReactor.advances KKDKKN1-1C1Cg1MM;;??1%D tAw!3!33 3G!%aD  %Qa,DG, KKDKKN1-1C1Cg1MM g% %!!!$$ %s*C C( C##C(c ||i|}|r|j||yy#t$r[}tj}|#|jtj ||n|j|g|Yd}~yYd}~yd}~wwxYw)N)r)rrvrrrr) r(rrrjrrr)rrs rrzFakeReactor._in_threads 4''F!!(F3 6||~H!!'--X!F!!!'5H55G 6s BA A??Bc|jr/ |jjd|jr.yy#t$r}tj|Yd}~2d}~wwxYwr)rarrvrr)r(rs rrz#FakeReactor._run_threaded_callbackssW&& %/((,,Q/1&& %!!!$$ %s = A%A  A%cJ|jd|j}||_y)Ng?)rzr_run_threaded_callbacks_id)r(rs r_hook_threaded_callbacksz$FakeReactor._hook_threaded_callbacks%s __S$">"> ?*,'rc:|j|jyrA)rwrrs r_unhook_threaded_callbacksz&FakeReactor._unhook_threaded_callbacks)s 889r)rrrrrrrfrmrhrzrwrrrrrrrrrrrrr1r2s@rr[r[xsj  M  )# ( $D ' &2 4%-:rr[)r)7roros.pathrBrr[rrrHunittestrrrtwisted.internet.deferrtwisted.internet.errorrtwisted.python.compatrtwisted.python.failurer twisted.trial.unittestr landscape.lib.compatr r r rlandscape.lib.configrlandscape.lib.reactorrlandscape.lib.sysstatsrrrr4rjrrrvrr#rrrrrrrrr,r5rUr[rrrrsV  +/,*+%-*)2;,5X&&5 X&&8__D"Z"JH>hH>V'7' 0?0?f$$!!((< ( (    "(V ! ! H   q#q#h r:+r:r