ϪfbdZddlmZmZmZmZddlmZddlm Z ddl m Z ddl m Z mZmZmZddlmZGdd ZGd d eeZGd d eeZy)z$ Test the memcache client protocol. )Deferred DeferredList TimeoutError gatherResults)ConnectionDone)Clock) StringTransportWithDisconnection) ClientErrorMemCacheProtocol NoSuchCommand ServerError)TestCaseceZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZy) CommandMixinzO Setup and tests for basic invocation of L{MemCacheProtocol} commands. ct)zp Helper test method to test the resulting C{Deferred} of a L{MemCacheProtocol} command. )NotImplementedErrorselfdsendrecvresults !  rc^|j|jjdddddS)z L{MemCacheProtocol.decrement} takes an optional argument C{value} which replaces the default value of 1 when specified. rs decr foo 3 rXrYrZr%s rtest_decrementValzCommandMixin.test_decrementValr`rc`|j|jjdddddS)z Test retrieving server statistics via the L{MemCacheProtocol.stats} command: it parses the data sent by the server and calls back the resulting L{Deferred} with a dictionary of the received statistics. sstats "STAT foo bar STAT egg spam END r!spamreggrr#statsr%s r test_statszCommandMixin.test_statss3 zz JJ     7W -   rcb|j|jjddddddS)a9 L{MemCacheProtocol.stats} takes an optional C{bytes} argument which, if specified, is sent along with the I{STAT} command. The I{STAT} responses from the server are parsed as key/value pairs and returned as a C{dict} (as in the case where the argument is not specified). sblahs stats blah rer!rfrgrir%s rtest_statsWithArgumentz#CommandMixin.test_statsWithArguments5zz JJ  W %  7W -   rcZ|j|jjdddS)z Test version retrieval via the L{MemCacheProtocol.version} command: it returns a L{Deferred} which is called back with the version sent by the server. s version s VERSION 1.1 s1.1)rr#versionr%s r test_versionzCommandMixin.test_versions, zz JJ   .2Df  rcZ|j|jjdddS)z L{MemCacheProtocol.flushAll} returns a L{Deferred} which is called back with C{True} if the server acknowledges success. s flush_all sOK T)rr#flushAllr%s r test_flushAllzCommandMixin.test_flushAlls' zz$**--/1A9dSSrN)__name__ __module__ __qualname____doc__rr&r*r1r4r8r>rCrFrHrMrOrUr\r_rcrkrmrprsrrrrso$  Y                XX       TrrceZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!y )! MemCacheTestsz9 Test client protocol class L{MemCacheProtocol}. c(t|_t|_|jj|j_t |_|j|j _|jj|j y)z{ Create a memcache client, connect it to a string protocol, and make it use a deterministic clock. N) r r#rclock callLaterr transportprotocolmakeConnectionr%s rsetUpzMemCacheTests.setUps] &' W #zz33 9;"&** !!$..1rcfd}jjj||j|jj ||S)a Implementation of C{_test} which checks that the command sends C{send} data, and that upon reception of C{recv} the result is C{result}. @param d: the resulting deferred from the memcache command. @type d: C{Deferred} @param send: the expected data to be sent. @type send: C{bytes} @param recv: the data to simulate as reception. @type recv: C{bytes} @param result: the expected result. @type result: C{any} c*j|yN) assertEqual)resrrs rcbzMemCacheTests._test..cbs   S& )r)rr~value addCallbackr# dataReceived)rrrrrrs` ` rrzMemCacheTests._testsJ$ * --/6 b %rc|jjd|jt|jjdy)z If the value returned doesn't match the expected key of the current C{get} command, an error is raised in L{MemCacheProtocol.dataReceived}. rsVALUE bar 0 7 spamegg END N)r#r$ assertRaises RuntimeErrorrr%s rtest_invalidGetResponsez%MemCacheTests.test_invalidGetResponses5 v   JJ # # 2 rc|jjddg|jt|jjdy)z If the value returned doesn't match one the expected keys of the current multiple C{get} command, an error is raised error in L{MemCacheProtocol.dataReceived}. rr!sVALUE egg 0 7 spamegg END N)r#r0rrrr%s rtest_invalidMultipleGetResponsez-MemCacheTests.test_invalidMultipleGetResponse%s< /0   JJ # # 2 rc|jjdd|jt|jjdy)z If an END is received in response to an operation that isn't C{get}, C{gets}, or C{stats}, an error is raised in L{MemCacheProtocol.dataReceived}. skeysvaluer(N)r#r7rrrr%s rtest_invalidEndResponsez%MemCacheTests.test_invalidEndResponse2s2 vx( , (?(?Lrcjjd}jjd}t}|jj_j j jjj|tj|tfd}|j|j|tt|||gS)z Test the timeout on outgoing requests: when timeout is detected, all current commands fail with a L{TimeoutError}, and the connection is closed. rr!c<jt|dy)NzConnection timeout)rstr)errorrs r checkMessagez0MemCacheTests.test_timeOut..checkMessageJs   SZ)= >r) r#r$rcallbackconnectionLostr|advancepersistentTimeOut assertFailurerrrr)rd1d2d3rs` r test_timeOutzMemCacheTests.test_timeOut;s ZZ^^F # ZZ^^F # Z$&KK ! 4::778 2|, 2|, ? |$ 2~.b"b\**rcjjd}jjjjdz jj dfd}|j ||S)zY When a request gets a response, no pending timeout call remains around. rr3rcj|djtjjdy)Nr r)rlenr|calls)rrs rcheckz0MemCacheTests.test_timeoutRemoved..checkZs2   V[ 1   S!1!12A 6r)r#r$r|rrrr)rrrs` rtest_timeoutRemovedz!MemCacheTests.test_timeoutRemovedQsc JJNN6 " 4::77!;<  BC 7 erc|jjd}t}|j|j_|jj d|j j|jj|j|t|j|tt||gS)z Test the timeout when raw mode was started: the timeout is not reset until all the data has been received, so we can have a L{TimeoutError} when waiting for raw data. rsVALUE foo 0 10 12345) r#r$rrrrr|rrrrrrrrrs rtest_timeOutRawzMemCacheTests.test_timeOutRawas ZZ^^F # Z$&KK !  :; 4::778 2|, 2~.b"X&&rc|jj}t}|j|j_|jj d|j j|jj|j|t|j|tt||gS)z Test the timeout when stat command has started: the timeout is not reset until the final B{END} is received. sSTAT foo bar ) r#rjrrrrr|rrrrrrrs rtest_timeOutStatzMemCacheTests.test_timeOutStatqs ZZ    Z$&KK !  34 4::778 2|, 2~.b"X&&rcjjd}jjdt}|jj_j j jjdz jjdfd}fd|j|j|t|S)z When two requests are sent, a timeout call remains around for the second request, and its timeout time is correct. rr!r3rcNj|djtjjdt j j D]}jjdjtjS)Nr r3) rrr|rranger#rrrrr)ri checkTimerrs rrz3MemCacheTests.test_timeoutPipelining..checks   V[ 1   S!1!12A 64::778 & ""1% &%%b,7CCIN Nrcjjjdjjzdz y)Nr3)rr|secondsr#r)ignoredrs rrz7MemCacheTests.test_timeoutPipelining..checkTimes7   TZZ//11tzz7S7S3SVW3W Xr) r#r$rrrr|rrrrrr)rrrrrrs` @@rtest_timeoutPipeliningz$MemCacheTests.test_timeoutPipelinings ZZ^^F # ZZ^^F # Z$&KK ! 4::77!;<  BC O Y u 2~. rc|jjd}t}|j|j_|j j |jjdz |jjd}|j j d|j|t|j|t|j|tt|||gS)z Check that timeout is not resetted for every command, but keep the timeout from the first command without response. rr3r!) r#r$rrrr|rrrrrr)rrrrs rtest_timeoutNotResetz"MemCacheTests.test_timeoutNotResets ZZ^^F # Z$&KK ! 4::77!;< ZZ^^F # 1 2|, 2|, 2~.b"b\**rc>|jjd}|jj|jj|j |t |jjd}|j |tt||gS)a C{timeoutConnection} cleans the list of commands that it fires with C{TimeoutError}: C{connectionLost} doesn't try to fire them again, but sets the disconnected state so that future commands fail with a C{RuntimeError}. rr!) r#r$r|rrrrrrrs rtest_timeoutCleanDeferredsz(MemCacheTests.test_timeoutCleanDeferredsssZZ^^F # 4::778 2|, ZZ^^F # 2|,b"X&&rcjjd}jjd}jjt ||gd}fd}|j |S)zl When disconnection occurs while commands are still outstanding, the commands fail. rr!T) consumeErrorscf|D]+\}}j||jt-yr) assertFalsetrapr)resultssuccessrrs r checkFailuresz8MemCacheTests.test_connectionLost..checkFailuress0#* ,  ) N+ ,r)r#r$r~loseConnectionrr)rrrdoners` rtest_connectionLostz!MemCacheTests.test_connectionLostsa ZZ^^F # ZZ^^F # %%'RHD9 ,  ..rcb|j|jjddt}|j|jj dt}|j|jj dt}|j|jj ddt}|j|jjddt}|j|jjddgt}t||||||gS)z An error is raised when trying to use a too long key: the called command returns a L{Deferred} which fails with a L{ClientError}. saaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar!r) rr#r7r rTr$appendprependr0r)rrrrd4d5d6s rtest_tooLongKeyzMemCacheTests.test_tooLongKeys    z6 BK P    4 4Z @+ N    z :K H    1 1*f E{ S    2 2:v F T    JJ " "FJ#7 8+ b"b"b"566rc|jjdddddd}|j|jj d|j |t |jjd|S)z When an unknown command is sent directly (not through public API), the server answers with an B{ERROR} token, and the command fails with L{NoSuchCommand}. rhrr!rrsegg foo 0 0 3 bar sERROR )r#_setrr~rrr rrrs rtest_invalidCommandz!MemCacheTests.test_invalidCommandse JJOOFFFAq# > --/1LM 1m,  -rc&d}jjd|}jjj dj |t fd}|j|jjd|S)z Test the L{ClientError} error: when the server sends a B{CLIENT_ERROR} token, the originating command fails with L{ClientError}, and the error contains the text sent by the server. eggspammrset foo 0 0 8 eggspamm cNjt|tdy)NsWe don't like egg and spamrrreprerrrs rrz-MemCacheTests.test_clientError..checks   SXt,I'J Krs)CLIENT_ERROR We don't like egg and spam ) r#r7rr~rrr rrrarrs` rtest_clientErrorzMemCacheTests.test_clientErrorsx  JJNN61 % --/1QR 1k* L e  NOrc&d}jjd|}jjj dj |t fd}|j|jjd|S)z Test the L{ServerError} error: when the server sends a B{SERVER_ERROR} token, the originating command fails with L{ServerError}, and the error contains the text sent by the server. rrrcNjt|tdy)Nszomgrrs rrz-MemCacheTests.test_serverError..checks   SXtG} 5rsSERVER_ERROR zomg ) r#r7rr~rrr rrrs` rtest_serverErrorzMemCacheTests.test_serverErrorsw  JJNN61 % --/1QR 1k* 6 e  89rc |j|jjddt}|j|jj dt}|j|jj dt}|j|jj dt}|j|jjddt}|j|jjddt}|j|jjddgt}t|||||||gS)zQ Using a non-string key as argument to commands raises an error. foor!eggr3barrh) rr#r7r rTr$rLrrr0r)rrrrrrrd7s rtest_unicodeKeyzMemCacheTests.test_unicodeKey s    uf ={ K    4 4U ;[ I    q 1; ?    1 1% 8+ F    1 1% @+ N    2 25& A; O    6 6{ C[ Qb"b"b"b9::rcb|j|jjddtS)z; Using a non-string value raises an error. rr)rr#r7r r%s rtest_unicodeValuezMemCacheTests.test_unicodeValues&!!$**.."?MMrc|jjd}|j|jd|jj dd}|j|jd|jjd}|j|jd|j|j j d|jjd t|||gS) z Multiple requests can be sent subsequently to the server, and the protocol orders the responses correctly and dispatch to the corresponding client command. rr r!s spamspamspamTrh)rrfs0get foo set bar 0 0 12 spamspamspam get egg s;VALUE foo 0 3 bar END STORED VALUE egg 0 4 spam END ) r#r$rrr7r~rrr)rrrrs rtest_pipeliningzMemCacheTests.test_pipelinings ZZ^^F # t''5 ZZ^^FO 4 t''. ZZ^^F # t''6  NN " G   0 b"b\**rc|jjd}|j|jd|j|jj d|jj d|jj d|jj d|jj d|S)z If the value retrieved by a C{get} arrive in chunks, the protocol is able to reconstruct it and to produce the good value. r)rs 0123456789rsVALUE foo 0 10 0123456s789s ENDs )r#r$rrr~rrrs rtest_getInChunkszMemCacheTests.test_getInChunks6s JJNN6 " d&&(:; --/@  <= '  + (rc^|j|jjdddddS)z L{MemCacheProtocol.append} behaves like a L{MemCacheProtocol.set} method: it returns a L{Deferred} which is called back with C{True} when the operation succeeds. rr!sappend foo 0 0 3 bar r6T)rr#rr%s r test_appendzMemCacheTests.test_appendDs2 zz JJ  ff - *     rc^|j|jjdddddS)z L{MemCacheProtocol.prepend} behaves like a L{MemCacheProtocol.set} method: it returns a L{Deferred} which is called back with C{True} when the operation succeeds. rr!sprepend foo 0 0 3 bar r6T)rr#rr%s r test_prependzMemCacheTests.test_prependQs2 zz JJ  vv . +     rc^|j|jjdddddS)z L{MemCacheProtocol.get} handles an additional cas result when C{withIdentifier} is C{True} and forward it in the resulting L{Deferred}. rT gets foo sVALUE foo 0 3 1234 bar END )r1234r!r"r%s r test_getszMemCacheTests.test_gets^s0 zz JJNN64 (  3   rc^|j|jjdddddS)z Test getting a non-available key with gets: it succeeds but return L{None} as value, C{0} as flag and an empty cas value. rTrr(rrNr"r%s rtest_emptyGetszMemCacheTests.test_emptyGetsks- zz JJNN64 (/:~  rch|j|jjddgddddddS) z L{MemCacheProtocol.getMultiple} handles an additional cas field in the returned tuples if C{withIdentifier} is C{True}. rr!Tgets foo bar 8VALUE foo 0 3 1234 egg VALUE bar 0 4 2345 spam END rs2345rfrrrhr!rr/r%s rtest_getsMultiplezMemCacheTests.test_getsMultiplets= zz JJ " "FF#3T :  U*4H I   rcz|j|jjtddgddddddS) zO L{MemCacheProtocol.getMultiple} accepts any iterable of keys. rr!Trrrrr)rr#r0iterr%s rtest_getsMultipleIterableKeysz+MemCacheTests.test_getsMultipleIterableKeyssBzz JJ " "4(8#94 @  U*4H I   rch|j|jjddgddddddS) a When getting a non-available key with L{MemCacheProtocol.getMultiple} when C{withIdentifier} is C{True}, the other keys are retrieved correctly, and the non-available key gets a tuple of C{0} as flag, L{None} as value, and an empty cas value. rr!TrsVALUE foo 0 3 1234 egg END rrrr/r%s rtest_getsMultipleWithEmptyz(MemCacheTests.test_getsMultipleWithEmptys=zz JJ " "FF#3T :  3#-A B   rcb|j|jjddddddS)z L{MemCacheProtocol.checkAndSet} passes an additional cas identifier that the server handles to check if the data has to be updated. rr!rcascas foo 0 0 3 1234 bar r6Trr# checkAndSetr%s rtest_checkAndSetzMemCacheTests.test_checkAndSets7 zz JJ " "66w " ? ,     rcb|j|jjddddddS)z When L{MemCacheProtocol.checkAndSet} response is C{EXISTS}, the resulting L{Deferred} fires with C{False}. rr!rrrsEXISTS Frr%s rtest_casUnknowKeyzMemCacheTests.test_casUnknowKeys7 zz JJ " "66w " ? ,     rN)"rtrurvrwrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rxrrrzrzs 24    M+, ' ':+" '/" 7 $$ ;N +.                  rrzceZdZdZdZdZy)CommandFailureTestszZ Tests for correct failure of commands on a disconnected L{MemCacheProtocol}. c\t|_t|_|jj|j_t |_|j|j _|jj|j |j jy)zU Create a disconnected memcache client, using a deterministic clock. N) r r#rr|r}r r~rrrr%s rrzCommandFailureTests.setUpsm&' W #zz33 9;"&** !!$..1 %%'rc.|j|tS)z Implementation of C{_test} which checks that the command fails with C{RuntimeError} because the transport is disconnected. All the parameters except C{d} are ignored. )rrrs rrzCommandFailureTests._tests !!!\22rN)rtrurvrwrrrxrrr r s (3rr N)rwtwisted.internet.deferrrrrtwisted.internet.errorrtwisted.internet.taskrtwisted.internet.testingr twisted.protocols.memcacher r r r twisted.trial.unittestrrrzr rxrrrsY WV1'E ,UTUTpA L(A H3,3r