o 2&a@sdZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlmZmZddlmZddlmZddlmZddlmZdd lmZdd lmZddlZdd lmZddl Z!dd l"m#Z#dd l m$Z$ddl!m%Z%ddlZej&rej'j(ej'_)ej*+Z,e-dZ.da/ddZ0ddZ1ddZ2ddZ3ddZ4e j5ddZ6dSddZ7ddZ8dTd"d#Z9Gd$d%d%ej'Z:Gd&d'd'e:Z;Gd(d)d)e<Z=Gd*d+d+e<Z>e j5d,d-Z?e j5dUd/d0Z@Gd1d2d2ej'ZAGd3d4d4eAZBGd5d6d6ej'ZCGd7d8d8e<ZDGd9d:d:eEZFGd;d<dZH  dVdAdBZIdCdDZJdEdFZKdGdHZLGdIdJdJej'ZMGdKdLdLeZNGdMdNdNe<ZOGdOdPdPeEZPGdQdRdRe<ZQdS)Wa^Test utilities for the AWS CLI. This module includes various classes/functions that help in writing CLI unit/integration tests. This module should not be imported by any module **except** for test code. This is included in the CLI package so that code that is not part of the CLI can still take advantage of all the testing utilities we provide. N)pformat)PopenPIPE)mock)StringIO)six)Session) ClientError) WaiterError) AWSResponse) load_plugins) CLIDriver)EnvironmentVariableszawscli.tests.integrationcsfdd}|S)zDecorator to skip tests that should not be run on windows. Example usage: @skip_if_windows("Not valid") def test_some_non_windows_stuff(self): self.assertEqual(...) csttdv|S)N)DarwinLinux)unittestskipIfplatformsystem)funcreason2/usr/lib/python3/dist-packages/awscli/testutils.py decoratorPs  z"skip_if_windows..decoratorr)rrrrrskip_if_windowsFs rcCsFtj}|j}|dtj}|sg}tj || dt|S)N data_path data_loader) awscli clidrivercreate_clidriversessionget_config_variablesplitospathsep_LOADER search_pathsextendregister_component)driverr!rrrrr Vs   r cCsbddl}tdur/tjtj|j}tj|dd}tj|s-t d}|dur-t d|atS)NrbinawszCould not find "aws" executable. Either make sure it is on your PATH, or you can explicitly set this value using "set_aws_cmd()") rAWS_CMDr$pathdirnameabspath__file__joinisfile_search_path_for_cmd ValueError)r repo_rootaws_cmdrrr get_aws_cmdas r8cCsBtjddtjD]}tj||}tj|r|Sq dS)NPATH)r$environgetr#r%r.r2r3)cmd_namer. full_cmd_pathrrrr4ss  r4cCs|adSN)r-)r7rrr set_aws_cmd{sr@c cst}dttd}tj||}t|dz(t|| }|VWdn1s/wYWt |dSWt |dSt |w)afThis is a cross platform temporary file creation. tempfile.NamedTemporary file on windows creates a secure temp file that can't be read by other processes and can't be opened a second time. For tests, we generally *want* them to be read multiple times. The test fixture writes the temp file contents, the test reads the temp file. z tmpfile-%swN) tempfilemkdtempstr random_charsr$r.r2opencloseshutilrmtree)modetemporary_directorybasename full_filenamefrrrtemporary_files  rPc Cs|sd}|jd|d}|r|}nt}d|i}|dkr!d|i|d<z |jd i|W|StyK}z|jdd d kr?nWYd }~|Sd }~ww) zG Creates a bucket :returns: the name of the bucket created us-west-2s3 region_nameBucket us-east-1LocationConstraintCreateBucketConfigurationErrorCodeBucketAlreadyOwnedByYouNr) create_clientrandom_bucket_name create_bucketr responser<)r!nameregionclient bucket_nameparamserrrr^s(   r^cCsttt|ddS)zZReturns random hex characters. Useful for creating resources with random names. ascii)binasciihexlifyr$urandomintdecode) num_charsrrrrFsrFawscli-s3integ-cCs |t|S)aGenerate a random S3 bucket name. :param prefix: A prefix to use in the bucket name. Useful for tracking resources. This default value makes it easy to see which buckets were created from CLI integ tests. :param num_random: Number of random chars to include in the bucket name. :returns: The name of a randomly generated bucket name as a string. )rF)prefix num_randomrrrr]s r]c@s eZdZdZddZddZdS)BaseCLIDriverTestzBase unittest that use clidriver. This will load all the default plugins as well so it will simulate the behavior the user will see. cCsHtjdddddd|_td|j|_|jt|_|jj|_dS)N AWS_DATA_PATHrV access_key secret_keyr:rsAWS_DEFAULT_REGIONAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_CONFIG_FILE os.environ) r$r;rpatch environ_patchstartr r*r!selfrrrsetUps zBaseCLIDriverTest.setUpcCs|jdSr?)r}stoprrrrtearDownzBaseCLIDriverTest.tearDownN)__name__ __module__ __qualname____doc__rrrrrrrrs rrcsHeZdZfddZfddZddZddZd d Zd d ZZ S) BaseAWSHelpOutputTestcs<tt|td|_|j|_t|_ |j |j_ dS)Nzawscli.help.get_renderer) superrrrr|renderer_patchr~ renderer_mockCapturedRendererrenderer return_valuer __class__rrrs   zBaseAWSHelpOutputTest.setUpcstt||jdSr?)rrrrrrrrrrszBaseAWSHelpOutputTest.tearDowncCs*||jjvr|d||jjfdSdS)NzFThe expected contents: %s were not in the actual rendered contents: %srrendered_contentsfail)rcontainsrrrassert_contains  z%BaseAWSHelpOutputTest.assert_containscCs8|jj|}||kr|d|||jj|fdSdS)NzkThe expected contents: %s , with the count: %d were not in the actual rendered contents: %s with count: %d)rrcountr)rrrr_countrrrassert_contains_with_counts  z0BaseAWSHelpOutputTest.assert_contains_with_countcCs*||jjvr|d||jjfdSdS)NzKThe contents: %s were not suppose to be in the actual rendered contents: %srrcontentsrrrassert_not_containsrz)BaseAWSHelpOutputTest.assert_not_containscs|d}t|}|jj|||fdd|D}|d}t|dddD])\}}|dkrB|d||f||krV|d||||df|}q/dS) N starting_fromcsg|]}|qSr)find).0argr start_indexrr sz;BaseAWSHelpOutputTest.assert_text_order..rz/The string %r was not found in the contents: %szBThe string %r came before %r, but was suppose to come after it. %s)poplistrrassertInr enumerater)rargskwargsr arg_indicespreviousiindexrrrassert_text_orders$    z'BaseAWSHelpOutputTest.assert_text_order) rrrrrrrrr __classcell__rrrrrs  rc@seZdZddZddZdS)rcCs d|_dS)Nr:)rrrrr__init__s zCapturedRenderer.__init__cCs|d|_dS)Nutf-8)rlrrrrrrenderszCapturedRenderer.renderN)rrrrrrrrrrs rc@eZdZddZdS)CapturedOutputcCs||_||_dSr?)stdoutstderr)rrrrrrrs zCapturedOutput.__init__N)rrrrrrrrr rc cst}t}td|-td|t||VWdn1s'wYWddSWddS1s?wYdS)Nz sys.stderrz sys.stdout)rrrr|r)rrrrrcapture_output"s"rccs^t|}tjrt}||_n|}td| |VWddS1s(wYdS)Nz sys.stdin)rBytesIOPY3rMockbufferr|) input_bytes input_data mock_objectrrr capture_input+s "rc@sXeZdZdZddZddZddZdd Zd d Z dd dZ ddZ dddZ dS)BaseAWSCommandParamsTestNcCsi|_d|_tjddddddd|_td|j|_|jtddid|_ i|_ td |_ d |_ g|_ d|_t|_dS) NrsrVrtrur:)rsrwrxryrzAWS_SHARED_CREDENTIALS_FILEr{z'botocore.endpoint.Endpoint.make_requestF) last_params last_kwargsr$r;rr|r}r~r http_responseparsed_responsemake_request_patchmake_request_is_patchedoperations_calledparsed_responsesr r*rrrrr;s$   zBaseAWSCommandParamsTest.setUpcC(|j|jr|jd|_dSdSNF)r}rrrrrrrrUs   z!BaseAWSCommandParamsTest.tearDowncKs||dSr?) _store_params)rrdrrrr before_call\rz$BaseAWSCommandParamsTest.before_callcCs||_|d|_dS)Nbody)last_request_dictr)rrdrrrr_sz&BaseAWSCommandParamsTest._store_paramscsRjr jd_j}jdurfdd|_njjf|_d_dS)NFcsjjdfSNr)rrr)rrrrrmsz=BaseAWSCommandParamsTest.patch_make_request..T) rrrr~r side_effectrrr)rrrrrpatch_make_requestcs    z+BaseAWSCommandParamsTest.patch_make_requestrc Cs|||\}}}|dur||||durEt|j} |dur4|D]} z| | =Wq#ty3Yq#w|| krE|dt|t| f|||fS)NzGActual params did not match expected params. Expected: %s Actual: %s )run_cmdrcopyrKeyErrorrr) rcmdrd expected_rcstderr_contains ignore_paramsrrrcrkeyrrrassert_params_for_cmdss$      z.BaseAWSCommandParamsTest.assert_params_for_cmdcKs||_|j||fdSr?)rrappendr)rrdmodelrrrrbefore_parameter_buildsz/BaseAWSCommandParamsTest.before_parameter_buildc Cstd|||jjd}|d|j|d|j t |t s)| }n|}t &}z|j|}WntyL}z |j}WYd}~nd}~wwWdn1sWwY|j}|j} |||d|||| |f| ||fS)NzCalling cmd: %s event_emitterz before-callzbefore-parameter-build.*.*MUnexpected rc (expected: %s, actual: %s) for command: %s stdout: %sstderr: %s)loggingdebugrr*r! get_componentregisterrregister_firstr isinstancerr#rmain SystemExitcodergetvaluer assertEqual) rrrrcmdlistcapturedrrerrrrrrs:      z BaseAWSCommandParamsTest.run_cmd)NrNNr) rrrmaxDiffrrrrrrrrrrrrr8s rcs(eZdZfddZfddZZS)BaseAWSPreviewCommandParamsTestcs(td|_|jtt|dS)Nz-awscli.customizations.preview.mark_as_preview)rr| preview_patchr~rrrrrrrrs  z%BaseAWSPreviewCommandParamsTest.setUpcs|jtt|dSr?)rrrrrrrrrr z(BaseAWSPreviewCommandParamsTest.tearDown)rrrrrrrrrrrs rc@s6eZdZddZddZdidfddZd d d Zd S)BaseCLIWireResponseTestcCsPtjdddddd|_td|j|_|jtd|_d |_t|_ dS) NrsrVrtrur:rvr{z botocore.endpoint.Endpoint._sendF) r$r;rr|r}r~ send_patchsend_is_patchedr r*rrrrrs   zBaseCLIWireResponseTest.setUpcCrr)r}rrrrrrrrs   z BaseCLIWireResponseTest.tearDownrrcCs<|jr |jd|_|j}tj|||d|_d|_dS)NF) status_codeheaderscontentT)rrrr~rrr)rrrrrrrr patch_sends   z"BaseCLIWireResponseTest.patch_sendrc Cst|ts |}n|}t&}z|j|}Wnty-}z |j}WYd}~nd}~wwWdn1s8wY|j }|j }| ||d|||||f|||fS)Nr) rrr#rr*rrrrrrr) rrrrrrrerrrrrrs,      zBaseCLIWireResponseTest.run_cmdNr)rrrrrrrrrrrrs  rc@s6eZdZddZddZd ddZd d Zd d ZdS) FileCreatorcCst|_dSr?)rCrDrootdirrrrrrrzFileCreator.__init__cCs"tj|jrt|jdSdSr?)r$r.existsrrIrJrrrr remove_allszFileCreator.remove_allNrBcCstj|j|}tjtj|sttj|t|| }||Wdn1s0wYtj |}t |||df|durQt |||f|S)aCreates a file in a tmpdir ``filename`` should be a relative path, e.g. "foo/bar/baz.txt" It will be translated into a full path in a tmp dir. If the ``mtime`` argument is provided, then the file's mtime will be set to the provided value (must be an epoch time). Otherwise the mtime is left untouched. ``mode`` is the mode the file should be opened either as ``w`` or `wb``. Returns the full path to the file. Ni) r$r.r2risdirr/makedirsrGwritegetmtimeutime)rfilenamermtimerK full_pathrO current_timerrr create_files   zFileCreator.create_filecCsptj|j|}tjtj|sttj|t|d}||Wd|S1s1wY|S)zAppend contents to a file ``filename`` should be a relative path, e.g. "foo/bar/baz.txt" It will be translated into a full path in a tmp dir. Returns the full path to the file. aN) r$r.r2rrr/rrGr)rr rr rOrrr append_files   zFileCreator.append_filecCstj|j|S)zzTranslate relative path to full path in temp dir. f.full_path('foo/bar.txt') -> /tmp/asdfasd/foo/bar.txt )r$r.r2r)rr rrrr  szFileCreator.full_path)NrB)rrrrrrrr rrrrrs   rc@ eZdZdS)ProcessTerminatedErrorNrrrrrrrr(rc@s"eZdZdddZeddZdS)ResultNcCsL||_||_||_td|td|td||dur!g}||_dS)Nzrc: %sz stdout: %sz stderr: %s)rrr INTEG_LOGr memory_usage)rrrrrrrrr-s    zResult.__init__cCs t|jSr?)jsonloadsrrrrrr8s z Result.jsonr?)rrrrpropertyrrrrrr,s  rcCs|dd}|dd}|S)N"z\"')replace)commandrrr_escape_quotes=s  r FTcCstdkr t|}dtjvrtjd}ndt}d||f}t}t|tj r1tj s1| |}t d|tj} d| vrDd| d<|durJ|} |durPt}t|tt|d | d } |s^| Sd} |sui} |rjd |i} | jd i| \} }nt| \} }} t| j| |||| S) a]Run an aws command. This help function abstracts the differences of running the "aws" command on different platforms. If collect_memory is ``True`` the the Result object will have a list of memory usage taken at 2 second intervals. The memory usage will be in bytes. If env_vars is None, this will set the environment variables to be used by the aws process. If wait_for_finish is False, then the Process object is returned to the caller. It is then the caller's responsibility to ensure proper cleanup. This can be useful if you want to test timeout's or how the CLI responds to various signals. :type input_data: string :param input_data: This string will be communicated to the process through the stdin of the process. It essentially allows the user to avoid having to use a file handle to pass information to the process. Note that this string is not passed on creation of the process, but rather communicated to the process. :type input_file: a file handle :param input_file: This is a file handle that will act as the the stdin of the process immediately on creation. Essentially any data written to the file will be read from stdin of the process. This is needed if you plan to stream data into stdin while collecting memory. WindowsAWS_TEST_COMMANDz python %sz%s %szRunning command: %srwrVNT)rrstdinshellenvinputr)rrr r$r;r8get_stdout_encodingrr text_typerencoderrrrr communicate_wait_and_collect_memr returncoderl)rcollect_memoryenv_varswait_for_finishr input_file aws_command full_commandstdout_encodingr%processmemoryrrrrrrr,GsD !        r,cCsttjdd}|dur d}|S)Nencodingr)getattrsys __stdout__)r6rrrr'sr'cCstdkr t}ntdkrt}ntdtg}|dur>z||j}Wn ty2Yn w|||dus"|\}}|||fS)Nrrz0Can't collect memory for process on platform %s.) rr_get_memory_with_psr5pollpidrrr*)r4 get_memoryr5currentrrrrrr+s(       r+cCs`d}|t|t|td}|d}|jdks"tt|t| dddS)Nzps u -p)rrri) r#rrErrr*r,rrk splitlines)r< command_listprrrrr:s    r:c@seZdZdZgdZddZddZddZd d Zd d Z d dZ ddZ d8ddZ d9ddZ d:ddZddZddZddZd;d!d"Zd#d$Zd;d%d&Zd;d'd(Zd)d*Zd+d,Zd-d.Z  dBaseS3CLICommandzBase class for aws s3 command. This contains convenience functions to make writing these tests easier and more streamlined. )SSECustomerAlgorithmSSECustomerKeySSECustomerKeyMD5 RequestPayercCs@t|_tj|_i|_d|_|jjd|jd|_| dS)NrQrRrS) rfilesbotocorer! get_sessionregionsrar\rb extra_setuprrrrrs   zBaseS3CLICommand.setUpcCdSr?rrrrrrLzBaseS3CLICommand.extra_setupcCs|j|dSr?)rHrextra_teardownrrrrrs  zBaseS3CLICommand.tearDowncCrMr?rrrrrrOrNzBaseS3CLICommand.extra_teardowncKs |jd}|jdi|dS)Nresponse_parser_factoryr)r!rset_parser_defaults)rrfactoryrrroverride_parsers z BaseS3CLICommand.override_parsercCs$|j||j}|jjd|d}|S)NrRrS)rKr<rar!r\)rrcrarbrrrcreate_client_for_bucketsz)BaseS3CLICommand.create_client_for_bucketcCsh|||t|tjr|d}|||}|t|t|||kr2| d||fdSdS)Nrz?Contents for %s/%s do not match (but they have the same length)) wait_until_key_existsrrrrrlget_key_contentsrlenr)rbucketrexpected_contentsactual_contentsrrrassert_key_contents_equals    z*BaseS3CLICommand.assert_key_contents_equalNcCs>|s|j}t|j||}||j|<||j||||Sr?)rar^r!rK addCleanup delete_bucketwait_bucket_exists)rr`rarcrrrr^s  zBaseS3CLICommand.create_bucketr:c s~|}|||d}|dur|||jdi|}j||i}|r5tfdd|D}j|||d|S)N)rUKeyBodyc3s&|]\}}|jvr||fVqdSr?)_PUT_HEAD_SHARED_EXTRAS)rkvrrr s z.BaseS3CLICommand.put_object..) extra_paramsr)rTupdate put_objectr\ delete_keydictitemsrU) rrckey_namer extra_argsrb call_argsr_extra_head_paramsrrrrgs&   zBaseS3CLICommand.put_objectr?cCs||||}|} |d8}z|j|dWn|jjy5||r)Yn|dkr.t|Ynwq |j |ddS)NTrrUr) remove_all_objectsrTr] exceptions NoSuchBucketbucket_not_existstimesleeprKr)rrcattemptsdelayrbattempts_remainingrrrr]s"     zBaseS3CLICommand.delete_bucketcCsb||}|d}|j|d}g}|D]}|dd|dgD7}q|D]}|||q&dS)N list_objectsrocSsg|]}|dqS)r_r)robjrrrr0sz7BaseS3CLICommand.remove_all_objects..Contents)rT get_paginatorpaginater<rh)rrcrb paginatorpages key_namespagerkrrrrp*s   z#BaseS3CLICommand.remove_all_objectscCs||}|j||d}dSNrUr_)rT delete_objectrrcrkrbr_rrrrh4rzBaseS3CLICommand.delete_keycCs6|||||}|j||d}|ddS)Nrr`r)rUrT get_objectreadrlrrrrrV8s  z!BaseS3CLICommand.get_key_contentscs8|}|dt|dd}|fdddS)N bucket_existsT) min_successesdelay_initial_pollcsjdduS)Nro)waitrrcwaiterrrrDsz5BaseS3CLICommand.wait_bucket_exists..)rT get_waiterConsistencyWaiterr)rrcrrbconsistency_waiterrrrr^>s   z#BaseS3CLICommand.wait_bucket_existsc CsV||}z |j|dWdSty*}z|jddkr%WYd}~dSd}~ww)NroTrZ404F)rT head_bucketr r_r<)rrcrberrorrrrrsGs  z"BaseS3CLICommand.bucket_not_existsc C0z |j|||dWdSttfyYdSwN)rTF)rUr r rrcrkrrrr key_existsQzBaseS3CLICommand.key_existsc Crr)wait_until_key_not_existsr r rrrrkey_not_existsYrzBaseS3CLICommand.key_not_existscCs|j}|dS)NBuckets)rb list_buckets)rr_rrrras zBaseS3CLICommand.list_bucketscCs|||}|dS)N ContentType) head_object)rrcrkparsedrrrcontent_type_for_keyes z%BaseS3CLICommand.content_type_for_keycCs||}|j||d}|Sr)rTrrrrrris zBaseS3CLICommand.head_objectcC|j||||dddS)NTr _wait_for_keyrrcrkrerrrrrUn  z&BaseS3CLICommand.wait_until_key_existscCr)NFrrrrrrrsrz*BaseS3CLICommand.wait_until_key_not_existsTc Csb||}|r |d}n|d}||d}|dur ||t|D] } |jdi|q$dS)N object_existsobject_not_existsrr)rTrrfranger) rrcrkrerrrbrrd_rrrrxs      zBaseS3CLICommand._wait_for_keycCs^||jdd|j|j|jf|d|j|d|j|d|j|d|jdS)NrzNon zero rc (%s) received: %szError:zfailed:z client errorz server error)rrrr assertNotIn)rrBrrrassert_no_errorssz!BaseS3CLICommand.assert_no_errorsNN)r:N)r?r?)r)Nr)NrT)rrrrrarrLrrOrSrTr[r^rgr]rprhrVr^rsrrrrrrUrrrrrrrrCsB       rCc@r)StringIOWithFileNocCsdSrrrrrrfilenoszStringIOWithFileNo.filenoN)rrrrrrrrrrrc@s*eZdZdddZeddZddZdS) TestEventHandlerNcCs||_d|_d|_dSr)_handler_called__test__)rhandlerrrrrs zTestEventHandler.__init__cCs|jSr?)rrrrrcalledszTestEventHandler.calledcKs(d|_|jdur|jdi|dSdS)NTr)rr)rrrrrrs zTestEventHandler.handlerr?)rrrrrrrrrrrrs    rc@r)ConsistencyWaiterExceptionNrrrrrrrrc@s.eZdZdZ  d ddZdd Zd d Zd S)ra A waiter class for some check to reach a consistent state. :type min_successes: int :param min_successes: The minimum number of successful check calls to treat the check as stable. Default of 1 success. :type max_attempts: int :param min_successes: The maximum number of times to attempt calling the check. Default of 20 attempts. :type delay: int :param delay: The number of seconds to delay the next API call after a failed check call. Default of 5 seconds. rr?FcCs||_||_||_||_dSr?)r max_attemptsrwr)rrrrwrrrrrs zConsistencyWaiter.__init__cOs|d}d}|jr t|j||jkr4|d7}||i|r)|d7}||jkr(dSnt|j||jks|||}t|)a Wait until the check succeeds the configured number of times :type check: callable :param check: A callable that returns True or False to indicate if the check succeeded or failed. :type args: list :param args: Any ordered arguments to be passed to the check. :type kwargs: dict :param kwargs: Any keyword arguments to be passed to the check. rrN)rrtrurwrr _fail_messager)rcheckrrrv successesfail_msgrrrrs     zConsistencyWaiter.waitcCs||f}d|S)Nz/Failed after %s attempts, only had %s successesr)rrvr format_argsrrrrszConsistencyWaiter._fail_messageN)rrr?F)rrrrrrrrrrrrs  rr)rnro)r)FNTNN)Rrr$r8rrIrtrrrCr contextlibstringrhpprintr subprocessrrrr awscli.compatrrbotocore.sessionrbotocore.exceptionsr r botocore.loadersrIbotocore.awsrequestr awscli.clidriverr awscli.pluginr r rPY2TestCaseassertItemsEqualassertCountEqualloadersLoaderr& getLoggerrr-rr r8r4r@contextmanagerrPr^rFr]rrrobjectrrrrrrrr Exceptionrrr r,r'r+r:rCrrrrrrrrs                    3   t 5;  EV