From 3b652bc3ef7b849e6cdfaf5534a3c6162c34516f Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 25 Oct 2019 15:23:45 -0700 Subject: [PATCH 01/12] WIP. Start writing signatures --- .../tests/stress/single_thread.cprof | Bin 0 -> 122523 bytes .../tests/unit/_metadata_flags_test.py | 135 +++++++++--------- .../tests/unit/framework/common/BUILD.bazel | 1 + .../tests/unit/framework/common/__init__.py | 42 ++++++ 4 files changed, 112 insertions(+), 66 deletions(-) create mode 100644 src/python/grpcio_tests/tests/stress/single_thread.cprof diff --git a/src/python/grpcio_tests/tests/stress/single_thread.cprof b/src/python/grpcio_tests/tests/stress/single_thread.cprof new file mode 100644 index 0000000000000000000000000000000000000000..3ae627d1c7b80c4b0b408adb7e9e285beb3b9656 GIT binary patch literal 122523 zcmd4437AyH)jp2G0K>kBD9YvnqB5u`qLOJ4L=g}K1UJ$)Gd-6pGt*;r4=_wzV@#qZ znrQMxvuWJo5=G;dsEKAVpG%auMLRL#ZfE<5OB9Uyf8VNG=ib|OyFoHOzkffEWij{E zIj2sYI(6#Q_Thx?TXs0B)D6EahfHh97FOmO$Bg$2*_QnHF}bEO;~R3#&Dn;6pKHz6 zEl`bFm2I5mHx%%3#p(EazJ5YY={G2?dLZ$>_K&-+djH`~^^)nlvHO;VliKrYQgf~$ z(>%$`<-F$Xq?Ngr>?E}!3*4*yNwc!6CwZ!^VPbo0Ms-Zg7gRRWGHG?Tb@ilXf5oJ> z4sg{vxo*m&Y-@W2y9@$P@~S%v38E zXJ%hvCL-@j?35ZLo)V?`nh`6IVXpOlh5hLdD+GT5^r;&Dr`1 zJxW?0gNX|N>7Qh7G!-jdg+FhporZcf_qwsb)e@G{U>0fcq(X3TtXz2R_MOI&}b&!%X?3K@7&i~Qj%e}ztnKo1-3O0BQ&us)37SzW%Jq``?-k+)*W<6 z-2rut+0_S3Z0mptp4jZSwy&MIcIuS$l!NQCo~I!vrC}vna;;R4nQXnDrb@7e8+w6% zCSFU+%N;j9zcM8mS}kqy)5hYbSD@6&mW*0OJckfZFQ`S6-wbQwzlA=m6R)(P)N$y} zvr>`)qT{+u4moy1{|z*%nhX}IwPN==Sl7vFquQEj$u<_++t?zSoeDg~>o`{G zm~U(LgK@V^(Mv6?;gPK2%_l!~{D7wJDao*gN!`$I%QQBsz;ONmMT^7JnnF6)Mvo=a z3=g5ulF6@vHJ?QMM-#s@a-bDw;e$UHBUW)}+HZr&D5RTIu7#S3ZjRzRvG}npZW?rh z9Sk_RVW$fBXk=SjZ<49BmPQMPbc0n4=w)RZ>^h>k_`Q1wpHl} zBwPASYxeWj$*)!{&c!&f2C6Ni3O>zkGAF}OU7tx{6ZS|+h9c2g^9PEgmSTnd&Ne{R zE`}cI#Cz()hyVD4lXgr=1|4-|H65<^uc8w61YeLXH1F4_rz#)`hRhvOk_i|nrSKK= zIIZk@1VOROS!^wf8HN4CD(ok;_zEBVA9L6rj-~|T8T{9r%QU9jTQSvLMZdfBBckXe ziobN5{L(`U{!=d*wE}-eyEhVqNg$QC?S$s-`nbfyZqeR`c~PRUOM4O9nZ)L3Gn<{} zMOP`_?7BpSVsR$IX3rPU?D;i*VPzsG{wNLwOuWX_Mb{nk3pBgU*om5gCE>)hIn%PD zF~d1#mi(Pd_BXA3^(%LM@JzjAz&$5-C4N=sAc5?3UV}Tm&4OQ$2yTQE8Nx02MTy{* zm@$p#Fk`SshI5PkTUD^XW~=%dwTlB+iS9#CRe$0R5GNDwk>CAu$GvO*T`w66etaUh z<1Sioj)E@s;eDPTF#GTC)O$7)fUALt;QPK*;4P>jA{a0%&g+y`o}8iUnTSG zdl+{(toH#}z*%V>^Bg)7hP%LzI+`HgAjpr#ZTZ6GgWs%|3`iZ{wPQN@;}DJx)QB)x z5FAn3d1d0-eF$&?K9r^-Dc1P;%nF+OYQ9P^jE56Rl+?e72#wv`p+=i6%#fPXddx*1 zVu(n67fB$oNYo=Wu65;oWaQQB!qyBMLO-eFiz

Y>?eY1h7SfE zSfoO^I3wW{$j?`{ZT@4ZtWLbutFGwxyLWa?Nv2b=pJUiavzsvSI=@u&e)mxy)JsNv z#ekef5GJCtl2I2L5JvTMXfN>DKeW#KhxO`W1G0i3Ok^4+8TB;{QsPWNU5zAYh=@Um z*FOwO`gy+*W0v3KS1|CV8?rBo^CTJiJzY0z$g3=dLzSls>pzEz7JHh1qh%S>Gl4y4 zl(CMs9%-&8pH8$gUir|SX~Lu=lRP=}zX+|?iTBa`eP%s4_VScuSnY3gSttK5qaZ6Y zt*u#Y#5h>FJ|_OCf6|lH!T2{6Hw=?_&%Sy3e*a#R@@xhMgs~8{8cDH7OGdlmVKn4B zb8ou)yBjY`c{VelyP`YeUyDXV2-nNDX4keU46oWq8cVtPd-pA$G#`$T&DcWMqmcTE z<|zWMj-R;4g^%=2c{UR?vyQ}?aP0Ndo4h|9F)ZcTjOx%>N?KWNMP4Srl0nV18}&Nf zs6lB6ud&%o8|agQ;c&8K=Ij-nqdKu=X@sI$3lLI1oi?6{neHI6jDO0Sg`#fi#I@L+ zwsuuu;!3=~koWU2VOeyWK#>!PmuQOAPbm}Q7xqg@hR)F}eDVLxJ~twm`kA?unFfY2 ziCu~2E~0T98i-b7$@T!2ex~Q9a}5Q?s7ni3?p~I2I;SmncTbe-ACz0kSs@FKX2JVd z(6k4|G?Rr?>&Zkq7;jnTesQCL)1~mxcFo^HJ zbqz`|@iugPZTXMZp@hw#z!(;IoYftGS!}kUy^u{etn{1X@oxa>U)TYS7ZFi*$BR%W zqX@K-v+fF0Z_w9M_hAGvGs{vV^PGFQ_8%r|L6@1V%!&qjCFheI{B3f23G+-`A7DcF zEz7!$bb3uTvkI{Zs5@9tI&je)Ee;mKfIZmIKM{FcRl)&4Wm|HqZTz!LTiWhH+cWY0 z=smIJ@`mRSdI&OBTS{v{209yJ2@qpPW33LveUsf zo3Q)+zq?{wbLym&XERXxC&}8?l>4q}?ftE2_pxx)N+XQuM0-O)uUu8pMa(ONe zg$fI-`X@Su27eiU@h6g0ufUk0NZ8GT65&P`6uAt4H1gYeWz=r~jPAcb%hbSFOM6Ks zt_NXAWOb&wJzGhQL*r_CVPqKUR6Rf^CN2l263zCuMp)ux>rfiUI`n2848B3Bpbk5w zI@O1|o)O78p;PE*U4mMb?>C9;+9(YqMMubH>hfY3-~s0Uzr+E;EhpN@Smr|=bd08Y z&qyw`6wanI)UWHpJ5BAa@Xd0~-0Yw=vN*uBdU_3(0WpJxwi@l)25k*j1y*3EO*2Me zyDETn^r*+FR2we_6B&Rd&a>3b{Fzy}p(G_yjfxC-w+P5Yk{{njzT zRz|&uzoMg%)f*M*U#VfN(Xs2NesA-$n0LSM#>4NPzxOEU?lJfXV#gAOiG(S<_s(08 ze|wLiDR4-)pv0IBJT!&%9_|f@tl^m8e9u%6obQ>6^A~n&%GfR=;E*G&jkwikSc@YLRvjbnGfoBoMN)F1Khtubg^icK702Ba}VK1Rp7)S_$? zN>(2=wKKAwo@k%2V2obCQP^A%$fyJ(ORHYM-oWz8h5gGkUc5E*q~w1f3%wfvp{;bj zov!C#iie3vLNe+aEt1k6_@6q6AW1GZb*3~MNw9;K1H9fr`xTV%naC=XWCC}v^b2C1 zLJ(&+f!c^~FkjlyIFukY4)e!399Ho-+|tl9^!Uq@|l#lb*(Cp#(Xvz`ostQeCHLM*V(d zbU6J|6W-)TKbX{p3^xeJ^-r{+l1mxaUfs6KA!ZEXTo5!nI!a@K zOD!bn0Bx9omgz#buuyO7`hndcEW<5p0lS;*BKf-&H%H{Lr^$G(<-=-Z!f)oveNx`; zd(GN>-p)hN{*M18i=D>63{2UMA9``lM#8vShHeq|g$7Y@uEwYgqGHhjKO*z8X4$}P zLtFN#qIL~AY%D{>Evq%}GzhFX1hK<(ho5b3H2rEtJDrq@F5IU^k{P8kvBMORT?=NK7TJT+siqmS zE$o6!f>~Y!CNA&&WXVUXO0&!$lWEfk8B63$5ux&CLcSI-a5`F6aUOt!G0@^F#p3LQ zaiA=V5=>Otqk>En@tCWi~6Gr=ZP{C9`?dR%dV~CxzASQ%xRcrN@8OyI-I2+q4f(&`l zhPj@+^rkU~3z-2URSLx!nIu}Vh5?+AlO-6c=PX!eCYw=)B17<~m;Q3dTXTPy@@%G4 z(GiKQO4v^VQ;B|4b9+A6t42v|3;iKK`ofI9wI`-Ln@ON=KM72nzH3ai1I~oTw4zZq z)`zaYX>`Y%*oqN2OysUZ(A=14x0I~&+sxMAI?3rz(l1JTl58tFU$9GhKuR*~n_4A~ z<5)cilYKAK&=DEub-4V|`wq*V$G^!pVR$9}`BZz{DAGgDv``K^=C67NFbykr2O5ys1quT=w7_r=}!h z4NGY*G)+${vB{j}(6y@+i_;(F_$h`yTBu=7BYW4m)MF;zcRyJ+^022Sq$Ja+KEmH) zZjmDrtLjs!>N`Q!VAAv)EKCL4?eqe_S>^9@|78m#a5&y-Gi;tQAm>lR6usD&-fKFqw`ax# zX2GRgoPkOeUX$?)ZN6@x(EOQbCpw1Buor6{PG{s}08ixTg9+(297v9_VM|ESI2$7? z$i1N%3j-8HsPM)Uc{iM7bgEw(saJuCQ>!F(4#RP&54-r-zxFuz_>^ZeLM)Vu{Uk8k zMy$xMX22{h0&;a}D3*wF zyJsu5;=7Ma*Qgt3yj)*%BR>xLxGGhs1r9>97Ga+@ z%^eBabgFNHUaa3cFmY0@TdM_@KSOcokGQptQV6XoDjTOY)@d9}E!X;mI+gV>c4qa^ z85(FunLE{&P3@{sM37}tf|Y@RYG_wHMl`9Zz0i)MrjyLkZ?=&p>Gh`Q_WkgSzMN`wMk#d zt}}?_M|g5z;`G98z);5qJKJLo7cV+0y%1M)z=w!VHcL&kB0oU2!ULi9WGFq5#rRyh z5lOK|V?-YzaD@_aX2v^un+}u*Cp#JC*1_&o5Q6_V48l6`*65R!3saKe=t2hkmoNtp zMwiGG`HrKWYJK;>1u4&Fpl(UqHf)qy?~1Gvq;^ycLKs8xr@@6(`ERq8oUu6IHXOxJJAxa7rPh+7vO?;Ujwq z%|~THZvtC=M#yt`n=aQ#daDi85^t1YqXOwo5LW zhclZ|%Mdw`>v)fB2OXNBIN&@77>NQbg=^bR!AdLz0^W9(9G}~=RCd$#W@N` z7!-#S@@W{FHSFVlxuqLZp3MkDZ<8S`d>M=}ek`mMit`hmJV{h*j5Beq4yS~Ua(1e7 z&`hyD<-kDkwY{Xhg9NRP#0sG<`X^(8y0aXw15&9{i5;EiFaK-n{6DEDU3N_?V(KvPHsGK%H%28%mH!2 z&H-oks>@LC(rIXpVh`eo>8Dd5&c&{d2(Vhft>q*ePNJLxX`SjiBkU?LaY|t%w~#B~ zu9`fytKuZCX>Zx9!=(c3fhuI8qf^8KJbCtCKliPtTT`CRBrH7HD)p9CgO#hnb`s;B%)ocU(_U#~5P%SyL2kAC~xH=mvI zY=*6>7am@Rl(DJC?u+5-VzAYvO6fQ!37#0@x^;mC zk_?AiI!OLpdgTx4hWA(Ee>!pJ66zlSh8Bj~^__?W>Ze_42PB64CsiZ0LJ! zb(dlJE=Y#0FzQOBQ#$a3PYYsvp`R61Y_RV`t`5=aym9i+l=MO z|21b+XBfR8Xa)E<^)bm(0d;fI6ap!oPU5eUxKXmm#U;|P{n)Spae`KWj}x!nB#j+d z6Z0F`B;hLkhT5yYSod-p;`-;@d-JkyoPmW59&ClctH8vmR_Luf!?&v!+c#@>ogWk^&z%2Nc#(c-RH#G+w=WG`|nn)N_p>P z9yor#d1ph+KQ`JN?)|g-tGvga*=z005r?D@A4s~a(S|2*V=4TMLXIxTO)y#d<@Db3#H$(pDcAxUP*;L&R@n9^-GY>#~T}VguWD^)d&YaKOGdYHs(e!fgT9 z`#F^leJ}}a7`MM0`K*SHgTI3=l%+K1e{THOQ}b7hNloa!WqcLxv^L{TMF(XVLp3+; z;JQP*;}9HH3*q5%U7QFi?;)X5ni|)lUk1k()EuY+EN-Zj_KT;Zhoi@AP0K2`TPSEb ze`v0h7z~_hDRnTaKRVAOym`Q0G^9>2T!tW~#V~Z*QxFrd8yP_UVHi1!BX|StEOU_Y zD4zA6m&>&+%r*NB2r)z^CN(;E7QMpd8bc^-RC5W#?x|px`JNO<(xRj7AX=A$1%dK* z2-#2Y@TzVgu7EIPvQ1u0i)vgMaTe0pSHmxRKAux;;G}~n-blS3gj}2E#3rlR z-+uh|`)?ja^&63Zt$AHbhFG)_c6gG=o}C@Ii+X0}i(6kT+aQ#*HdVg3j%jJDxdWc$ zqf6|eT%{7$wkTdDgVqTfP~zjZ4M09=)vcVoz7&9G0?Mg}sw8s>d#+2(HPpkdVJ?K) z#jcc$PT6hqAr{#dZZad-5J`s>6P5+jviWJ&RYhlkGi-j}tZt>%en zLmN6_H%071*nPx|*nL;1@$-Q6Cv(wYfS&H*G+;(Mu~5ix6RlCzJ#k6xEjKJpFW)<5 zk8*_$tWoPx(3*1#xBJ)Wk#ebNl`gn*JDoO0U*Aq%Iv`TLa2PT66ZZ$(DYfcnREHZh z%|=V{#r$3B_qcx6qLf`14(A?I&)@fu&a3uLdDg*1BPN|AG>$aYOZ%jOdWFhhEr+-2 zXOoBad-K?osx#b#jePbG&v<$IG0+!dVWCnt8jx^dL_lnJsGw5tZX2@Px>>I8Awx!Q zu_wk}M5G>q7}3n3gC#thFi!cQOm|irng5vmerZm9492^FJ=hB01BUd^v%9bDd#zrX zqt5ADmAG3?->n!xw(B zfhImZln!Szj6O_4bNG!&>~%rmRMCRT2A6Fo-P!@tB}QA+{*0N4y)}OPo|qo;1SncY zdmT)KiX86)cRH+APwsw;1k02wh_a3-MQuhMxUTi;{l=CF#tjsRU>NwxV9zgEoJxEL z5Fax7CmBemD=&=1c>`?>UqnTUwQ^DiA|Uw+Jj5lwN9D;mg2H@rgbg05S5lR z#D$3q&<%VGMFz2K1C~w(QSa`1ANKAz8{zz0UYa*=c*`l%JMEwp*03hn4=4#TAcW~D@7yC6-Z1UwGtl3IU`WV#nJ_ohySqt^Cl|THRrN9A4zYlF{gZAB?RXM@ zDHV_)%B$6bD>jHG!2^$8L=_I~&eEpq4mzfKLU+{%3Rv11bmBKFo{7Jh3zWrzn$jEV zZS#c=3t;sx%0I+t?51kcRxfhjjo~zM?#kNHp8--akqsx3Q7-}?y3|;rWfBfqc6vS` z`868Ii*M$btH;a`g1h^jDn-b$Pp7cdnp-+cOZcDLr!HE zRELT!(;S;Ysow%!>B~rBFBbVNK&BH}wvmjzkmYOSW)AzX_z^Y(rP4#u2f$JsVs7*Z z7G$XW*e31ogMvB>rx?6K@MW$I_U@@Hh&L_VHUCb{1 z+mNi%QEb4V8psnMfp*fqHWSfO$*9_`6MDvAsX_?y{W@!-K>|NB1b3vRMi>Y;&{Vl&!UbqXt3|n0OZ)x@yxe_VrSd=~QnUX;ou92+&mn`2dWf zS*n3JhSHT#5DqEF5>X>Hcfo-_HtF zz$sxZbUF7?XFAXl4shCEmzI}|+C8~~Q5kG~TP?WPCi_@&4}U+8drI;Rc#c6|c<9dq z4V`#qU*_mY*dg$OvE?&(G|vXQCE{(*goVb#l|{~IRX7PWjlI#HOTfT$oCfi4!~b*= z`p?#pwl?l|fD{LXH!+ywf>1ZT51olb)Ffle9*n9M2L+Z!l^G~*1c(2UX>H)t#s4w-lTLya?lbICH`i4e zKER+9?%8;9@aDSf>im>vGmt44rv1s#JzOoqWBuU+NzSFQk#1!RzKVi&SM7bkWbOiX z%!~!U6RK{(Lrrpwg$3tnGqoI2gyMxOVimC;+bhJr8%52;9TzS3H158z%!Gc5xNA0J zckxuSL&2f25X9keLU*+p@+tigNwJTgw;P*KvlA&dChmcH^?TF+AXN}sZ<6dQ8R z3P<`qXzR_XQ-BNy$ng?S!>V}*qVd#Rk;RyZIg||K#A5zesT{R%@y#=NC=|wRT&MYT z6ah%sksVP0uMRluN!>vk#KG}z{fn}p!CR<10eCoyIM`8H4c?QL#Z5k}EYAvJxg7Uj zfU|M~8PRH6_7IlEjv`&Qu#PwFq%$ghXNJS4GPA%^JHDu9D6QL^sQI=0dKmCq&8spn z1>pWPhAr_J&f0WSbH?Lwys(f{f3*k{01~Q=*m z)lCi2Sp4(QJ~|1OWDrR;OU!$w>>MS;;!OL&7l%-vEyUY0aYPbFA`tL-gp~6Xsk6Jm zmiYi*vH!FM*R5mSKYmNBkx^tgw}nPhuszdhEbQw52<0&tNzjENnqf=q$r6Z}U^k*J z5^mozJt1;bbV6`v#ct%RH~0!3j*IMbLACTRs_Rsc(ltnU)dM=6y#p(9KfT#FFwpKG zz(q9mfJY03lOm_e;AS9d=08Z;);6nlIjXe}jETcOF z%mgFQ`e?*mic~INMLHpY}2vj7bm}>u*ng_fJ`u=6G}`pNV(OK{v0tcjU2n z)hoz+3Xj58fF8w3B+4Xk-LY-p@Nb-U(-n8&HcvE@?x5G;b8tks#b3*p72swpV?ieJ zD6(YKx#$BivB;2bS0LluR&l`4AIc(}jy83wkI_6a)o@_q^r}QOaj^r%a?Ve2sNq5+ z-kq;r@Y4KyaNYbXkIfpq2$@bb(~vuwO2NdnAMRa}hNBJEJ4fW}ZiD4sVqxNXE-G#0 z_!2>w1Z@86ZpXKl5ayw4rr_RGX1o6`=%uNJ|wb zwm460Z^czCKs**K=p>MKL^*6Jh80bzye(Bt88#Y@L*LLc8u%v9)GIz&1lr-UIEv_B zSnqBIBy_r55OX(F=|Fr@mp}#yiaFh2sWOEPn$^4-(NkaCPG=`vvo!LK4CJ;%14wdM zMrYN-@;LIrBtdWM@n>KyA1fom#+pypJ=+jGh{5$reNZ%rorbCicJxo=jY?gH`uJlY zFg%{FuU-bjRdi|_j^5uGY?i;3NOw)+5^0|Y3etABe0nABqtIH|2yXNRwm}<~>>dAKv^O#^J0-VyL}>B#$&b~bpr2rJ<fl<0~DM;Id0 z2!j&cWXRBGHchLk&BZdz+zj24jWs6BwGy~0r%9IWw+H1g% z*ec0%x&~d>1c~&b;Ko_C2QcVFN=s&&<%`SPw9gUR3{$&Ej7gq|ssa3&;vjSE=tBUP5!>66(-|B0&M!JY+L*Ay!!|=0&5~vO9fDr-_VM35Vbu zm^j5M{eCr$OR?XFl9WzrGjfk<6__|ZS1;4JC#@CsGhfFH35KmJTWM^jQ;mZLVUVZ- z6DN4Ev!fx6Amo~KdQ7fq3~x#dZfFe7{WTukG?gd*{O*Y4>cp!(?#wYAZ{kde&2Xl2 zBU;vf0`v7CXcUQq`it8yX}`f%pa_H1epR{z=b5HFWIjFTF7M^$G$g;Im2* z*NQmmXm8kl7R1!8U_#DrNT$*wFj1NP2F1Zk4du+l+jq(v?Y|j&L`pJowQ%(w7ev)D zHlUAcQ4K>|YlF42fhfTqJ20fDwPXkKq#d)G$T`X(7wjE2;`j~Vy!7f+rps=Ea6B*MX+ zPHnY9LWG6X9aNMkk$2}`+4HE$@1(plzJB=Ow{8FtdsZ`K#DNiv-Nir63iSr8hqKjc#nzKt*@VKY8`=%?boYhzf3E7P(Ag zGcqx$ee$oLe(qr0^*VCty|3>%;m?o~pV^4vbYKMMYn0OXGTqYRTC7?7 ztb{fkdJmo6CQ7J{{)zogXdVYfYRH4e>^-_VpQ$4Jkd#IQls;SWh2wSftoes;`VWpN zeGvigX-B_y-{lu3b(j-&{?hWDK6g&at6%=&?az<<5~nBHSU*MXhw4q=yl66w>k4qn zH`B;_M?$-O(AUNdZ#WHo^7Cii@W{pYWc74K%Bu&7RqTZF$ITJL*fe|X<1yNC(ojv~fqyEr6 z2j}OEhYuLPGSY$9qXP%aQW42G@PhwE)?#paCa#IZ%{{b0i+K}I7n-1tNMQ`0$sh%+ zPq${gEKZ+-RPc`$ob!sAjS;8s^v%criiWhAPW5v(UbM08CxMYF@i7S3<_&)JklX%x z%j%RjarK9{9JF{H8k@HO#Be$=f^!`0;;tg5;ONY1ztB-hT(S9rGyIqakH83}>qu!( zI@9h^Ec%%dY<7%^=a$2!A8_;~xJF^@qr>mK^qg~(s^Y*1flx!D8uj?zC;VytCd6k8 z8|VkTpofJ17-s#kbVLVXfdH@X@>xjJjxo78g@qW$6LnvC$Md)R{hYsD*a1)bh#OA2 z>cwxM0?x4DzzEL28VR+xV#$NMb5>+^v^i>Q-kI9(joU8$YRa=28Q?ata8I0l)(^-< zy2wu7$PCLho|W=!#@e19n8&K|+Bb=SKeh4hyEokr+hH@p9x15D%B%e5fsam}^yM>C z-XBI^*`a>FQ7^=3+w>9PP3R?p-+>qWTL}LU`H8mQ`Nv$a`zcRiqpr;)h}3=(7{M9x z5XJe*jYp68^K(rpuhYBpggLK)XSbOg7{M9JEsFE(o#%ez3wxiI@&-4b`pKR@Q;Bcq8w*MJ>0PY~VJuzl=KnoG;WKrTYW~ zANZ@&wE2k4ksWyA*WvV=Pzsx0`Q{_9IEhccjV;(%FE1KVSxqt0s<4YP0xx8AxNS1U z8SM;rXCFN2*l*`k-c3*K{KpUGU65oh^zQD#XzDjkzO!4)%^fM%;2zld!s_CPOv-CL zw&N$~|5NGFRkO+P4Hh)?sdbFZEmTaI9Nm8Upf^@edM4%B3@1mr7 zaCcoq{ms$3!&AW-yTj=Tuuv(@LVd9 z{Y#HrGv|9Jq`dZ#H%)lt@KYfg#{+O+1m{ygr=B)ALmtjL^u;@7{^zZf*Rgxgcb0wS zU%>e&h@*N{U<4;O=b9#uYNFYIfz#yn$YH1YeYy5IFvR&+D4zcQGO+GY^GU!MAG5cff1Yx_hQyehH>Y0j9F(&n82(9V-cIz zn}=z{fh3mj0URDViBWN?n?S{ZAr&2f+MD9;lMXz>c65h`jWER!fw!58s3S0fdT^q4 z$XwPg#3xAGfdS4f-|Dh6kMRe$J=KQCv+(BjL5I{GP}i7U9Xz}}5!2}QwG-D)osz~I zKv~b5M94{H2dYbZqn5>C!PX(`H|E;(17gv!>LDuKuxl;WkN|e}$&G%!h!`=*=NiY@mlfZ-opc8JlwmKlI83_&N zz_8)2`2R`6nTE!*-bP^Y1D&qgM?#4eYZ`%JO|9KY6x!DaBhL~#K86EB!@=2s*)iyZwGZBZ z_VQK#hhWO6-#oF?;kR)D<=}K+1n1SXcD3n63ujiEyhb`<#qlWuBbXl}%a0?03wZC% z@XDBYhvx^@zI4&x>E3{UkGtTtJ9kCs`T@f9s0Krvj9N$DiHjN(@gD5`1qlYlfg#Rt zh#nH$GqV(~WK#$35nq`Uu8!=>N)Ux15rGjB-=!$@GF0^Xbz{v%bPv|k*B<~-eZ`<% zWU9Dq^`O2^FRVh}^o+&F9k^h{>F5nz<7WI5BKP}onuTCtaQDM3#I-zJt=GlQ5=lj_ zVu`kHjlJIInR^~D-SM5ZN&ce)L(x-|3IU65>Kr5x$+^rkk%P%{ES;k7i7);c=nrK_ z6RQ*xGUpNXIY?q;3|qL_!CqU_sThQZ%?xomFoN@oi8#%~68A3JP1^}L9T>rRej-kz ziIG`k0!{};a5h%QX$o$tuZGjY2+l7h;*=g{;S+E=FoJXW4qKggOJ~IEY?Tf-M_?@K z5)b1R2hGeX+<)!!;{T(R%Bff{1cd%Y{01iy=)hP45sMJDAZ2y!hOU7C74<8$8V-!$ zY=At}>(s|+cQc}mR5HQRIWU6LJoB=!UExyU3bVDa?VS1>ULUa&qD|VuX^VI^dEJe5 zi}EUUGYXH_THM7w2S#{36jfIv%W)d^HrP#aFC^h~U<4M?UW)kb2+(S63pmfQH`o>gcg0CJ*|iO9ATKqtY0!JV?fGxK0_I;#@Pn+ZzmT+ z(|(&d3#D=`d`A>#ionKQB*7%uc^Gj?I@PI$#wCPd5}=NBc*U1Mz-hR3S^@?(BW&<$ z8+9kp#K;=?#>S`$WFaAYAB0ObvFqwKIG42_ke;(J&|uya7_$skULv>z%izFBt;RtB z+lB_SFuGB;TT$0(DaC2(1beUs z*UKl=DI%|mb&9}9op{vMoGFd&o3lz4G#E!l#|k(wf^#l$&M{ie^WTbzI9%T9Raf-; z-8;JiXV9m0D2_=$4h?H{*ClI2xvAbeaQRoB9i7=l$Ii8!vLt(tAFY#N&lS_J(MRvvaj7M-;Uyi{vf;D=gMx0W6pYXZYlOs$;(%7GEQ;i2Igy-DBf)VKRB z1G()8aaAw^V&8D2-DxGGRyc=ej|#$5*V5_6B0#6r|w*?HFHTS~s zixfoPISW@GoYcpxkqa!-`$-;v10%Q>!2>JyC+<0XTcQc~o5e&eC2b}_+wCWb1q$}? zz;#sHji})Z9COW%gK=*&hQj@jXrf_4m25=iJtTXPG?YeU_51X|f2ID;czRbT|?K2-Xk3r~s3 z)X|v)nL03nH#}-z6FGQgrO9WYQB_JAt5^p({rtQQ?{WazPSw@ z@y*ar`+&IF5vL?~L}!>x5SRlaoQIbUM3vB9z2rT3yZ2=F^n%#sH6?1T zLS1u;3aJGw%KkZ}a{r9DZwb{f{WAh1xXG6KxV(Rgsoy`-a`E>!p&D-gbYLt_bAZ8F z1~j?{_rPouo(r5#+}wd7&VONmE6qUHDGpf17v_^APx!8Xp3Nk%Y(EK%MXwgpL#h1? zFqggyqQ$}0qh=0YpN99+9i%XHv0S|VS=8bUU5oT=Jn9JTEvQ`ce4Z1I86X)1Y$l-= z_LKNY(gIsq%`}7m&Xtws8S5bIto^BXpfvj6VsU5e-SpSm@TJ@%9%EhXqT!F;qB9;j zFl3!%d>(lV$SlG>M6OdOw}GIrnQCM#jF8ztGQ)LkbU&y}$J9c+Dm-B9R>y%6I=8Ve za6dAn_E{;FmfQc5&`vW}U~h4zp)hl$-`u#2k9y+NV$@l1bf#i$%H~s=$N=s*97LCQ zD+D6eu_A#8jEGBb+a0tx)3h}L5$-Ayh`uU~FZoZV}mB@AY|R#ij%P(V5iE4bBJ*alXfHu1)N4Hu2W<)%Gd5;wpi6 z2gcIz^$j$;=)M;cVlUKNX<|C-2q1xw10#gS>Yh$pvNbx}J#uKlCEHxX7Y=&19Qx3q z^M5$9a$`hb$h%&{VeG0nOgBcbVw7xhO|RZ)Cubj3wowrnOT`~d(=kLArIO99Bj9aq z1ikKcl`(^M;8?7$uS+Jh-4;p{+Kc@g8<7HWEzUPrqp}@V{e55#UVIe7%`F$#zG~W8Fv*MYJ8 z`d6~o)-KMrWZG8d@N{t0;ENHmFNed_0Oo=78vCxFMqXWa%{101`+h~h@j_0FFN42ySI%3+r-Rx@Azar{d zje2%FZmp@(Z?;{nHD(3|iZvQ@46CUo0^vp!iNQ$+#)_i!DzWxosQese(j6{#(01W&djOYGL>m-D+_Rl za@kA*Zu?34u*F^C5Tqu9eJFLfz-%9a^k&~Va`Bq%p*j#PK`~W}IR{pU!h0kHzkLx7 ztjpwD4Kd*1WfrD}8^TR!0GH{X8deT2*iGi$di8IJ1q|?bgifSha!o%l>Pd#)3^Agd zU&Fvgdrs=ZdI1Nd+TDPctFtJ_1_3{e4Di~}w_w*#*Qr(3N? zSHx~j7Qki9SK|$M*fbU@=#!hsyB=I<`c+*rcF|N_Rk5+^z;bYCkNySNLvXFQ2O042 z4Kry;vy}5my?uHzVZ)hS00zI>DjW=C>JWpmyy3AfVCI?K@je;qh2{w5D-y7SIWUfd z#+RM|>&2dnvkGHttO2Ej$-F?B=@K8Ygtj7KSfYoyCWc`onLWun61JaJF!TmLqEh#s zJihLC`z=f|^bQPgR((>m!7gWa{V9aVmginGls5-AA;$(otMH-@3AV_Ap^PH?kZ0mN zElvk7#briajhjm}=Dn~OX39)BVg&m z*ck5mwGNCZY76w(Zt|&U0qMt{VES1V7>l!{H?95D3^E}+2ZppQ%pw<@-2htbk;hFmF|{!=lu>~) zagaJNg7hZVv1We9(WqLN%=@&(rR3CXR?WTs596)XVxDdTWUvQ_w*E9$;6qf-xzo7x=D!BEbYB z<-l0<`V}Z_*bNrT!oe#_!6-*$2VMdN2gXwHheIoh!yO92gUeAmPM=7im4u?YCQG0wtV~u1Wv+E{-IPi85$@)kx3w`6w!=)LKdd}PMqpTr z9+cBKR1g=dh&K_ugyCvVq~Q|8l&It+P--QCp0nEvaD)6 zCB)h@ops{Vj*2CqbzlVTi9|afy)Z-P7Q0dB`eiPV2-42y63{y^g1$iXwSqm?jE)i~ zV0K^xbH6@hTrV48n$phekK&UFXCO{M@4yK9uM>UkV&7}cI6YLVYcmO$?I-caEM~O@ zZR{S_G5w=&%IkB~&wsf1(p*vxbzq3ICymMLz*+2jT&^*@6t6|`{jq2#G(wCxZwdT5 zFc!Dp2kusJAaU!!7q4t73r{&pn}FYevG`Rln%fHF1vcx38*81&y^(PQhB#}9u7>V> z-#NjvpXDo|4lmovFLC=?mX#Ad>_^Z-?E`OedRespOW^cHQmgFDyt>3gOdAGhC-Gkgc*%NFtooZKu zmH`wUN)ZoNGHRp&2?I%vMyfFeB)r_&X-H-GFD)mbm1M?X*g zct&oURkJX}8HRTH;f6!()@#?-EyVhU5iFJ^Z6=}9*-ru!M_xMvkFNSF+7mAv z+zy8+WV^PDhma66V`z)pvJDBc*p4$=A>O`RO-{mX^;QO+1UWk}l=D}hVx`NVz{TFP z{Z@0yR@7QpMGLwVV@?(3GLezSBK8?zE)JcIlU*}#rFd}nud}Dd>Cg!@92lW-3TX@w z8eKSlq-@ONh?P6d`9FK{u`|`Is-4EdkmWI`h&l~PabUQR*M*ZYjejhO?13bvf6|oJ z+9inDff1hfB+k8(amv_NMLi-g7H5f9f#4FahURRhwSB8|=W$$v zE-{wTFMs~72VVT)IJX=+3 zZu;i6x6ufxQ%b0?lv>LciAvb6eR)GSt=g;hSHr;h>he}|U zZ@}Jy_5v=ZPb@ClYxnXByI-KqIn!uwNKOJuW9!$y`pfA!4|8L%uyYvU^=^Y6k=+Ik zyx>2J@Mo9fm+L7FV>|7=9TF5kBcdFbD#RyrMqX(Q^s z8Y{dc>~)HDzwO42o?=#Nwz$tErStjby29GRLAe#D^DbDeluQCQ86$~`%=ztCk>)oGy zZz*sVdmVZ5L9_kDwWIAY78-A|JdLl7C6`GrZCU@9ALCkJ*H}0(t*b=*OSxZk&EH9Efg^Y-y}@bMR8yR=MzNyWHL^4 z2iZyN^5Ei+zzhCwP>p*o!fI_U?g2Ork{}8P#-jDV2bI94(2hJDiv;ANMmCdx+=^;5sM`PqIc?@Md<`uq=`$R=ro14D+NWV2n(myYhDsH`aT& z>0tD|kM0SaDbx&YR|Q6Ja?ib*LHHVTGdXv&%kAL7i@cl^a4!^a^0Q7{7{R%LFizcV zJTH*dX-Rc=V1RSWqAt7ObA^wG1-7~|1}YdnPUg5~rpY5Pto9H}aepM{xKgXRFqDQj z*3BGUOi(EY#^U!+MGq_X!SS2`eGIj*Witt=?WdpxHt0hxWZl1>sC&=z(G}n(CLoSj z=!%FVFv9b}l*s^dxUCBM^)|w~?HevM-zB0S9Ev1q`>Uz-_EPwS6#Aan(%kjjR|p9i z*8?vB>@)L(dDs2$oTPr@z);{fpb`C{Y{{W%W6zGms@&r28SUBDvP)tdO{mzYP;?6{ zG$v9eJEfOkH8H2~dJ_jzZp!N_&CwM(kwk{YiF9f6YAQR@A>V0n8zz9+##n`7oj}|{ zn@NzD{UnoTk=M6LWQbs&)xG8hJb2cE{ZlMy*LwB?pFV z)59+v3NwyFhFy2lq@FkEZEgJ*Lo=y1F81w~gT_9Kq8`MMIUagQCV*P$->06zX##qy zUoC?LF6;jtX1%AemVR_sW7hr?4j*{1@2bPazTG0<34OHmII3OTF+DTZVYXWo8s)o0 zInZtuTa;~VZ|Ex9Li`mBuk};C?nnOZ<;P~7k@o4tG8Po z8n;%B{u(!;zFpXW8v7a!83RvfZ6oiA`2RcZzfZ~3;5oRm?QQ=R))J4`Ra~2vfa0hF z*R@`~-+^e#xu|7qKI6dHrYzk{hI^&;j_o98XghofE$B%!PPMoQLqAB`g_!-5*o3{) zM*HH3ondKPhc2@07s+xTu&kA%tP_d^Z6*P={UrC2St(Z-vg|$~Z{(6!4u5#qvZPMv zz!2wu&}gL_s1&u+80=hYp5W&F^NNWK%aZ9-9|9aYQ3XaYUk6Zi8>9gj!>550LOu=*adJS@uLA@Zh5Ko?AQR7ABDZVG`^wXE?*94r7=$+$ zg;#?SoL?p4bCBSs{nLn(NpO&AP%3h_Lx8gijNoMW-Qvs;ClgsS@fJLK?FCc1@xF)v zXB8O1soz}+_*_ApOak{6e5&Io?s4HG5u8*=EZ6>Mpeyz^)2=xSx(>0q)z$GcO((}=>vs=cuzK<} z>7-8Uz>wLUS@)gMO2vNMHIF3*cW^@k=-;RI*EDi2I>44M!%LoJ*6Y8+t9_~==^1%h z98Msy-Hw%JojZ^)1DfqCT+L*cpu3t%sTp#>gmFf5^JhonLedzRp3!hdJLW!S%WQnR z<$on9{}5=9T5625jvF%xZ1Q&OlcDteU33?!vMRV8{arV!UR-gykcoWZu7Q0ftnYSx zziCNb$bn%O`aA2+#e?FoS-IBijMm2Eas}opi#al+Mi?wyEDq z3PU5ft8}S|(p7BF2#jq{y-UCiIGf=S>zlXsyQ%+ivo1;MQVtApvg@0pE;U_vp^L^k zn9}Is+~tDy)xS?Y#%ZL#LRoXJJG#DSs#co{>|iabe>W-?n*%v8w)&;#h;u@D7cpGI zw%SYrPWwq<1ZRmj_v=!e6;3(H`qvI$xo_RDT@&w^b706Px2vlo+5R&rs~WupS|@=Y zxzWZ$H`T|_NcKWW$d+5CE5HkW{qTV^0ti2UTJZ1(2XuBMsjCA+oO@HOT$d^K3%Xes zI#C+A*4hC_wl_6p)skFpG4Ak6dID-YOoT>%EGuwlm+6JZIUns%96F;N$8=f?d@={y z_`6yx&ysI;l&zS{8>5F~>#0}nx@Sao(xyB`rpA}!H+>d&Bic+tAGDtYMsTjDg6m5X zqPAkYhbJxTpAo0CrVPIIPwW6T@|V}$fw6p+UdE^5fZ)DREb#CKzyvWzM)w3UI9`H9 z?{j%J9w-Pqt`QzKXxWS~UIj)l4+7?5Uv4Ar(%qsIv_G7<`z>zEtg(Z2f=D8oR8b@m z7-5_T4~m1yxH(+h_3UdeRf{I6K^BfCqeXB|#_U&Jy3JGJ(8mFoILh;T?GzYu+v8otS&3&(rT8nd$0Vq3WH1u4dY_y=Rf0Z}6rUHBwV8yj zVm}2V(j$7~248Y2{T_lxcv5fi3oiJbgX;!kozdYxfr10W3Xp=&vt!u7p^@7=gu4*^ zGNSK?OCXx7Add`J6?u=q2=5mXdHWl{tjNqI`oS!SlX)eVbn(`id zX0Np~N9+w5I5-^`!O5wNJDay##l21c9@FEsx!*~Ws{;d^TP7r2LeP+FZD>~tQ-f`I zuG!Q+qF)IMG7bzWA6T7olfJznALAf7IB5DmJkm!`|M?Hz`uU|vb$4JW&z;%sHRuKE zit;vsko7O(o;z*izzEJgfVendW(FIJnz3`H3ujhfHrUHPZrX}=zqv5cZykfn1y<%7 z$D~(g@++JD6?Hthf_?4jmc~Q4r#+1Mns$iU^I$V%6&ThkBs+fVWb-RC2gd0-7Fsr8 zhIAd6INb@`ME9VB4vtfHG%ta&1G8O}51I1+i1OsA|F7zN$bkoSd7T$b3$%HBp`$H3 zeoU@u%y>_=HPodW^c6LA4ITQQi?R(_tUB_Ro%Z~K)|t&d%+&&1?x|xLD7S(yap%FG z{}wv8PCVll&P++BQ$30fh3C(!z{IuT)Q~@w@wp)+4Tdv~c$mA3ncc7<_0VrGJUr#u zOaim^lfcB84TZ_;6uOu{`^Z-K+LkL!2PV$nA`xaIWau~NyO_mi|9bPyJKi-l<=ISv z2<<06KHuCoNj3=9(ee(|~&t?*M zv!4Ve&f7xaZJUHPrxhvY!Md&ef-p*{5vL*T+9wKk||}DbHpSxU-)G zCeGbVky$?LsjP={*^Oyj9N1jB56@hg!3hikBn`lWFaF}(-+k}7l=sWG$9(Rn0e?h0 zu7|H28-N{{I8TQOPYv8uzrCE)9e&d354`kJ$~*b_rw5!pe7HZMlY(@e1#D=HtD39Nv)fY=(!wZ{(~mJewGGS1p*p#~GMZk%2~R zrHA{PH8%uf%Fi{VI4|Z=)EOzyX1JzHUi`I?gSxj|7#2+6*lq(#;r_8ahC=N@<}wjGXV3UhJ=>6Sol8R3aXX<@&PC zk0v4z30NmY=o}a!a+(pVRx@r$itpt^CG>B*RLnn;6&P7T^yxNS`W`=1>BKfF)+Ex< zwkCdaRcd-d6pJtYcXd05)J9jTo8n2me0-JrzoU02>5ZvOFW-ij0J>6~kC5P=6$$26 zA;9u97{X*3HaI?&L{N<5eYz6#;L>a zcn+I5!=7w>dR#&DwI>@tnbx0o1O$9mfe}6#c~?ykKn$nc=3>_w5^y>&f^#Z6cP&Fc z4b7Q6yLQNlbDARovjZcTCzD%lO^@L;3l_MC^NieCzn=BQgCT)_tWnh7IWQKd`V|D~ zE*3od_{n{a`EYc~JLaLq|NE_Vvw_n&$nC%o=U6uURZN2YEc#{#CczqC#E5jNF|11u zbB-e!MsVKBp3yr!JL_HuyWJK{Gs{T4D*&U0STV52I}-%pz<}8;S9IB7d)y?Oo!FLX zScND|eiHp-KR5Bfx`Pg>JD{#HyZV5MZ5_Ccdm=ov_O%n&PMwmTa&TSN^EBk7AQl>1 z8_|(;XH^(Yqkoan#%XE?hBY0RusUO}22ZCMjYy{}-w)pTrJDD*hMk%Up?zqIb}=+Gxvde}4u?k9=u#5e z)e!n@t8_PQ;N!F#iS1!mZ>zP3g%L3wfx!>gK;kYyALnF~HYeFFGoiO>N13p_9T>s? z8u1TW)Ybr(63cMrX^Z#}?zCY-1soV5(7Of%h6H%2N3%?@JSHQj6DN>xV1&eAk{FD) zRB&s11FF*XmDod52wLGYp>UW`$f`M*%_<&~D7&rOk-(>t(g~oj)hz;vzLaTP>3`;K z5#6_*!v%)Lq53*isAh0?$r3Dm#adVVCdX$9HPnHT)*agmeE+ZRRgs0RvxeW@wBMw! zro5M~`FP!zYW@TpeK6z`i^VxGg7b3VEaFi;bH7#jE#RiU8|=m*>;`vxlmlaNn_G08 zp{&pSmo2!Y1*bHBu%=-~X5sZoV~PVqocp0xY6?uV${NcOdMzR|n_;wt@P2n%BJJfw z-$HXbsRe%*M!ATju!Yy=x@a#=DY`lQjNrRxOSQZcVglJ8|?2%j7)7W+MfWe)$`B@O5e7b zPBn@FgQ(RhYm4>uYP10fjh!(}k%Ix&r1(E(ZE*29YtyCm*~I#A?=q}t_+X{s6@yP` zt18qd0wc_ZhChl^Di_|08BD{=brCoX0~`75rEbm7MFxj*aQFl^*dQ#7p}*ay0dt2! zw(>RZwn?P5Lev;b^iO8xf_e*^qE}`2PF$2KcZ^411n)g$xxbklRK~u&diyr9_vM8} zU5`6#oT%*)3EIXf!GsO9>!C5W`w2AfX1ZNc(!Pxt%xIarH+LTZH)?Tyt%dgO^^p^*W_44lww}|iiN?Bz@Y3rnyaYt6zzELQDXyLg56)TP zM_R!N#W*m6Hmq9Ih*%EARj;Vw(j(2xP;2ZyoEi36l*<(o*cB<*Ou_`qev;Uqusek< zu|K{;xkIT*^$g#M6IlmFaE2W$+9AyljPUgnFQ5F6%%r{aUFK-g;OW%Y*}ATQ!We3m zNBx*=MqNIsmUUN@v&>*Bu(3Y4ptV;DD!7;vI$c>kvy5W2^_6Lt8b-t7f}ojfg=`c) z6rZ%Vy>4Da^9$OZeV}w1>U3=L%_?sH&IoL(o5X<-ECcjy)j(U)LyR>CD+yC_pm zVmmw!vR%?odiJ*So>==yd)rJ!-lcb&>4}zy-Yc+IxlR~V+sUj-J~?l2qDz@)Jmw|E zO&l1?Snp|AgC2^N8SX!5%<-kAaIm#HDfUG+A5?)6#P_1O+Q$swVQV?|g>!Drh`v9# zcN({;=bBf?p9gUY2@zhdXSMEO=9vV+2RuSzEXY6fT?HgkVid*>QTkvA6FDm+8Ozfg zYIYDL(xjMpCPs(LYHUW>(N}OyDX+5#Kb)^r*dT&Nv@nA6B9O!#bn`OnI%Z|_4PE2| zXpv8adRpm)(wO<%sb>%EgX^q}i5>!d3fQdzBkZyn75(GnzGRy61x)o1p_md)u!Rwv zw^K*^>irgGaXlHgk@L1sY_vw4B^nX+1MScwaV(KR=m$A4!Y@oW_|;98z%M@PU!+?( zHqn6*+@VU=s8A)tqhBju{mNY*@Ku$d&8ol<=Ol>M=YdY#5|(bwdg*jbw!(*P6UI+< zncs1I>RrIKW$SR;Qmi4JLPCgL32y+QP-C{akcp8pivNu50na3blpPqsd^^=H*j`W` zDUeZ}QO!EA0B)_(nNVNvq3(|N5{|lBR+dUhuz3{zsO} z#Dab5Zlvo-j|h(jWt8&EVi>}=%_PX$ev+BH@VbF`hnVZz0_lwEWm|9b#%tt3*NU`?w7ShCNW*@TsG6XiEiGN+KTYjt;xPlQGCQ*1P-Qn{U1H&98jn%PDWa_xA7o`k5D})PJZW(QVmp z-27U@nsZgkJGbM1FCRFgJ*9qZ#@ceVhL>vynP3Rzthn~4*dKA8^Q2QochiaYe8V2s zz3`tcDeq4&b}yvAUNfC)4WJ;p@Sb5|11rnK`{=&<{Bt*)n)2?;{OL!J_w-XS@PC(c zJnfvL&iZH&4gj2T(vN=n_#R8*;O__EayDbv-S@uji38tEdE@WzaYOxvf5pK+FyP^# ziCs#Zl`veU;U*puGF!C6;dGIe+^!HN1L*TiTI?jNE$6ZQX zuR*FQwX<{w9#4``hJ)wkiS3lr~+TNWHP?y*l&-mmXj z-+KQMJL0U%g=h@awhD~p)6Wv;MTD=3z~c<>h)Ci)<0+8f&4h^> z7YBxXYMiTylkYsn>VDU+-hJSLjo(RmQwM)k+~NZ#dY^{Z*2oDFI`D!&gpbPBx@q2b z3#aTcyoEeF`z{?A;^gE>oy~!3aJn(mkx#G4;;2wI-I2|3Y9D%#39aXNnGTGlP^yDK zutKFN_^mjC(OOsu^m~&!lfVK;8lD2uGrQsVjHp|~%51|bASmDjk)LgD%%kU3DQ+qI zJxStp-Ahy}^Gw9xONgaYEj1QG2ep{EECu57`QW>7L>E8g=vcNsld!b)7lb2LNG&6^ zr~t&JsnKUo|Ar~YE!q}D=7#RT=o^rPX0qeGkk!{RuQGxN1qW93&$F3MwX&S7{Uk8T zA?tt$Sqe*?SYBJBDHwTel@iE`HdzU}WCg_H6S9pY8_es%tp{%&-1p8SuEjoK^V;i9 zdc96!4vK5D2?iZ(8WvutSM}u}R?Zy?-mX=KsU`;OyHD9L-+_O8`_L6R;lMo^6YDKHG*tsdx0YGhM&KP|VIgLMldNct+C{ zL_8GC6W*T(`(CUu$BLqSIVD7b7m=}^j1}=lO8;{FQz!DifMhyVixFbTh}9Y~2SIg9 zA5bD!0~hL|TQ~>Vx!PjDMfVbl^ z)Mk+Q9LX^e2};J6p*9tJ8~oT#CY)mKoR2HI$hP!#gWtUcz@8Q}Df20ER10%KSk zE#ewP>Gm^+&C*TH8IPtvY{WnUp~bblXgRBl<|P6z+FGLx?T0Y5LH$CU4vgUBm5b_P zDpK_25z)_Z`$izv`Cw1qUM(YyWGvZn1Ysgy#FhwIZA?~}s)Vg?^f%`H1XZa5BRKiE zx_SY0QI*h2SYsvu0FqR)Gn*XEuhq8zvJ%-N5rDRnAE7}XwWX^Te4K1Z_GnW|{A>>=LjRaf-; z-8&Of-u{`Ei@(2#7s^FD5CL5n!AVtC4W=2xs*A|&SRz%a0wXwekINa23^mw@e519o z97CMCJ1~Nic33Sh?>Tlans>pWt2X^&-=l$ZM>b1To(>FgE{0UpRg|Z;sWpmE3+P0a zz~!2mPQcIOXPy>TKSl!lRp2fD(wijGo%|%atq0%xlZn$NouD@al&uga8q^a%{=zBi zmmHl^4^agYBlPAb(V2QU*Hv6X7EU01)Hk=SD&4zNWsMq!z0`rR)$(}}uzJPd)C*)x zLSy;MXP*4-g-cFEQ~Z!skBUk*#+Zfd2{fph%|>7_l8SDHFj}~|-m72!;_c6mJ3&`V zPf?D5a;Y_JiRczZ*_*R$EU)!g4i@H^)(W-Ofnl|JQcBuUUSzZu>~vF10%rzmeM|o} z`;Bj;_5sexrdm~C1m`^B`I^D0hd(CX_0yZYKO8X(*W&!}jF+b$vvY`3Z#`$?{c+gj zU;XKegF+82VAG$9uUIeB-lYG__hUtei5Ul0Ac0*v517`!XaK%hclUC+DahNbD{horpKTV^c3b|DUi zLhb`V&0kCSzZ?AFWJQd1O)y6S_-2BiSPSq|jrN7ZlwG`$-E#o%55ztX!KmFKa&Vu3 z-IlZ9JbR)>8t`zvwQNu;)w}W#^*5OTDccM;QLIctpVHLrqk46QsdXnom;?^&ekqT~ zX5Po$6ail)K0{p`8r*DE>BPjN}uQJV{WvYiTm16O7}{w z+QPbdtgKdB1Ko4=ih6L$IaCibq3V$esIcb-tH`0mtmb&T?=@@lc{>kD*}8^KlI=*| z3vWF9?)iI<3dtS~vEYTlM!%uZfKx!YIV7TZvfgYnqVOSy_EXULx`n8RQq(&kiQ!ze z??u0=yRa_hef6#ncIx)(VW?5ii9(zXj3_)uulSYr*PsH5N$5SBHaGJhv`7#}-p?pN zE8B=ks3WGULem09`Vxdm7;P|GX*T}o=7R3ZL^x!8<5>@O@7{X>BGa3`_|Ad}}__j~Py*H1}{OnuE7SHUq4mH_-5;1MnCeftL+`W!?D2ioYULpl_MOOB062+Z2)h<7}qwXN@b z<=+!p%VBQqsVM~gsT?aGNg_y;;~TP!sMlpK= z^CH%u&r?W6YK_8pJD~!x7t1UIeLSxb&?`RT(7K{Zx&@m|00|Dxas)qs33LW8=!^`e zk*RtejiuHg5GK?DG>VEy!F&cT;)Yw*WAmR!K1|J}*TG{O z-rD%ATs}6SQB3$+xs<45189B`+KFpZ;~I4C z`)@hJHik8jWDXu5F=y7Jeoyaii|m2vX#TS+Pn-E$jQ3ZAhMGPkL6{Ytc;hAa-||=D ze&Nw)opkJ+lhOvqCS`FZ4On5I5L>KGk)8wwB&Prufi}N%F@t{HZzN2GuR@UxUe}HGH#ZwVw)+}F9(NVSQ(?yD&7Lc zjD_NJnmT8<_qJUPI);q*81ahIenjXMe;e>Wre9{^Ync1|qN#g-R@aI&HU>PzF#{UK z#0nELj(JXc7#j0%7u1F@gOR&-V3NNym0YZ^1tk&Vle+X16WW3C%f=EhA@2v&8?lws zT!c%$coHp0NL0S|kZ%IZ_c^J~;1P8ie9gNDlu;k|>{EC2xNo^;*(hATh=71QcuQ=&h+|(SF3_HvMG>SPC zm{VAG->uO9?MIbNK7qT}0yK(wIxu(Q%JprGW!D`>G=(UYTYyF}QM=|c@Q~u|6L$2b zZkmm@-cE>FYw)@%Dnt+bH6*Gzh1fME%(It~oeIrF={7}aTLowY)6OWGiBZN#`ZIZ{EzsbFM$15E&y_)Ez0ygA zWAc}g6@r}#{pIvKTn3-Cu!i)V`G`mj##32sP926%IR+6yK%;!yBcmp=ulBkWm#4mu zB53xqz8#AS{9wv;5lNDmxLWM~gl4)YMPYNNxmvmgxy|yody=^am;sGq9tq5ylbF&? zM7Lb=>Xyy>U}sk#N) zuNL~D{iusEpV0rwdh9J^c&MXxd7lsc^!PvNYx61S<10Z_6!iu&v*mM@0gZ~Xj5K2g za%=VUDhgwM=O;Z2&2M^tQVXe{hGizKflQ(?XZ6S4hx^~|IHqbCHLc&JwN z#niH0dnGIP@*

AuzBTx#A8XWS&P=?FfB#T4Orn`x;{USfda@3bY%klh!B|4{dbX zLY2$Q!Q~|8@?Oy6;g@-gI)3T#z3;@exNa&j8Cnr%8eKa5`BNa-IB9p8>;sk1Y6eQh zLnr%nv4|M}1Br+8tO8ws#f$lDd;1@BSuS<&t0adza-0>QQHAtC?f0Yy8Gah?cxZ&_ zS`4NboI<=og;nK>eIL@|;ZHS^kOIZp6v9d>rLNJ4VHI?KI+g5$6_v)fbYAjTh(=+j zQf=1l?#_}PrCZ}Y(+p2rbj0av43>ih=~&HqTt_)bSP84GBS}-?nfcJ+B6=gKynzkg zyT0caze&mUGsTI`(C31_s1Q9QwD|Yt#OIKihJbQ=Sgo1FJbNAj8pRw2%u|_X--tTZ zzJFO=>rUxt!NAL|nY_|aqj2lPy&hzY6n%Q$pbNeo+)1;LUgMfM>-2fYL$*HIBW<>@ zwB9(s zH#s&P?&a17+Pc;5R}S5&OWL$f79@5N?X~r;TROaVjLtfHUKoYeJIEb8P$ag5@#MJk z&RzprDjN%qM4OgmUaVc?_;7PeKqAH3#GUy)B-u{LHjAb8tR;L6PgX#bOgU^K5JkMW z_N282YeKT>A;2`ZBuTW9%L_!Yeqj`9+!gCJE@VzSbUuO5!;hHS?KDqzp%x$Kf4bcS zG3#QMDID4M@|e#y{cRwbdf;>d8s+&eV7>quH0rgOD=+phsQt zP#kwg*ILn4Q^Utr4#8dBR7Q?CK~m002KFEoW_X%}Y=`{)5+c76U6vg(2MepUQY9Cp!asvb{SDyb!fFMG5!RZ?T=8B& z#grE_C21QB6OS;iNRp`B@?xguB@s9{)mK%I^BW)aXR=GCO8x>R3Uhn?N22a@GL4QLeA zZ&VB07qwZRO<4#H#d{5wK1QRM^TBCTd+l-G5p>+v&vd4swSY%~-K@07*ioY<{M_K| zw1N{lbd2_TyA}hxy;Dxk=8a_Y3}~Q?Ltq7V`9ZT@hGt#PC#LE6;w+m`8p|h*Xseqp2aq?^KBS|%&-tl7qta7Z~ z2MU+aFuI_{1B)N|<;A%a9?%fm-(T>voguUkLaC^dLL)lltmc7@TsMj+6S) z;AH2rN-U@Geu(~PKhEatZeI(Jbuo3RQDqa#v69C34*COmkrjm){qhi4d5~yJwQ()A zYI7Yuvf73qDG#-ZNndg78qg@FUBGiaV-{djF$>Tr=6IC*8+s6*erT$;$O7WLgNr~D zzf2&YQOtqB9K@JDx5}Y1&1R=;V!J6>*HXqTKqHv-Sngc6tF^A5aci!v{|Dg}=v>sQ zY73vCBNd|DwMIPHPY&yque8Tj&R5Y_bxkj*9D|mTnV9J7ep<_TmaxNH3uIImee?Cb z?e==HU#@l>(172Y0QY-5Zl*_;4rEBKnTT3bM0(3=VF8U|ZpSO`{`YNNU!Q|1oS++0 zD-#-EevSrcd7RoRXowTCLp3;}czZUV?sgn~-NoQ38^q7$!ezo%zsoA7MayG4~xnwLMv2Waugw7 zsozv-rlN>FaaRZ3my)MWf?xkfC0vgZ_ID)=Gh;HtGec-6IaSQ?Of;77aL*Fxr|IlY z6xYgop8OZ(sDG4~9Ae2=S@TL=Ng)RPb7B!!vI~x%I%rNHzOq6s$;i3H%NKS=!9pXx zFkL|(Pk$&YyzCTR>TqHt3p1cWJp(f{m*8X?%nvFwRN#P~Hontd1l=(|ABFx5?Y9+sF65ex;5COoLU=VDNcyl23_bVxeuI z@_#dE6R;0Dgqi{Em`Ld`4n9$X zt`?+Qq|m`8t%NLmXv8jJZZU2QYDY3I&oLt_igQ!=AC;JGFxj{$O2VvtY`Yp;&mTg|UD#7~gr~(L z+P~Ap%DWDyh1cDdG~D%@O?0%rnSzmMk^MRk4Mf3AmhBnMFTew-2Y)@-DYrE0SV>N zW%r@mRJyZWp>BmjN~JC}&XiT7x%%~{Y$dCuxne*bh^0)(ODI;t*yzrc`;(#sB&u+t zY+!nEB_>7J#*K4!Zv#!dTV#e}G>UmUk(xVlV^V5{Yic85Za_tcm@yh)z5o{Mpu^qE z%4^0@`hE;MKT@XMF@lF$u)d&Iw@dQuEN*jF$=<-iL!()JA#yuP!@Z2An903&q@UPN zKyGswEtouqQ<2{ZI_^j`d+jj#BOrgBReu2510K#(#i9X0#~p^IC8OJUR6LYreGzh8 z=V$iWVP)ANpy4z&FFr5?Zf z%LJTA@A3tH8c4VAjsEu`E!wRDf`)uw@%tR7z}0&?$gSO zsMN{H!X$VVn}4>h!Oo$D4vd_l(5r}~;0ETZB)%>nl3mWgC#AX#T33TUjvvqi|0U4d zlMBwJpA!F%!)xFX?R3o(6ZhI@zqGz&Zvguk^f`Nb5uD&Rqmp|=Jr@#W7J1M*O%Tq8 zBzY#@W6erT$C?EmZjB@@`jXXO5+C_KD=0`+gF_5xik(K3m1D{>mAuW@|4>BLak>Uy z1!xr9Mz}8%kED0sd~#r(zTFnNgEEy;VHvx7aWu`&Q%v~?MC~8zim`H z_t&)Qd*RN;(tk>%_UtOsf;}>zz>grC{n00=`FCL>DT~jAj2N(a##NuSr85z6bZFNp z)GQxh**s=IqnOQLNH{%;F#ie0@rX|T!|Vf=yxKk;{c73tQy!jitY`dnf;Q)XzQ`;A zJsuidx((1rq|Ima=d7k8p|lPr%=u7PyftaeD4TkfOGGbqyYba(bn4;IvGyuPFQ3jo z$V;ucfYA%kC^{mNx~9X%4;$jKZKs4E`v`jNajl;j*mfc57yD3&bBhhakVdgl(dI$a zN4(Btm1AUgJkGq@>(@p{e@WI~K(F|1;ai-a@v?GgO{*N`rPe%@#FVd;Mlrh*W?eIE zDj809x4Hei9-JFfy(DaC!MYfzz0zdEoiuY!oMFLO)7BqU4TY0?*yi`DL2T) zkMxl1=J`}w=+&>cm+m%pY9MyXk{J}BQEYoY zQ>`_F%o_T~J|Yc2x=)`?{wYoTo^3G;(I_Sk?={sHGj@Kd^7+BnKV;^ec%)($qEXDj zz_h+FW!4h3eMFZ{|JR}`7M+%kX15>O_RXUv+a0>re`8g*8O@Hd0KMXS`ZzxGT%3*? zjQZ1n=yJlRPQ?&vX1FzVYP6L@OKYl!4Iy>=VuGJ(F|fAmGgjKcY2lGf*l-GqM0Ekt z8MXo}X&!nl<~=<~ow!KBC#5tn2*4f`RF1?b4P{OzJm5 zEvXQVV(x^o*{$Fq-imb5pU>SmKE3P#jbcK9=1F2U3sd`8IXp<6H(In=0{VC>4d@mB z1mM>*&ptBKurK8{%+{KJaBo?F2AI}@aY~sO$x$#uJamzZzGx3zfJQNo2j)^3YRbYf zCii}HI)}XEz?83)MlrEfF{{aBuA#r!hughPhvRb9G$u=^v|24hqsZ8FD(lg`bnO4> zxWtzpUvhn;FJZAR1}Q)TO!ysRClgw+28QAfc=&x&a{5oLxtVLK0FClF8hpCuYC{_d4m?@Q+)xtChg3*{EYVoTmUOB>YX#Z)m#GEGcgLEMA$^szN@66k3cCE=vs zcNmZ;^EXj}b&c%$OIkZzKNmWAhU!R%Gj8{E57IN{xru*#orgwY{|KGb5Exn74WP$E z&q#Jwg#BrY=^@Qwc`iftAlrik5A7B7+E8tfcIi^H5oI-{6;-rQf!CIMkI7An&YhGOZS4hU z0B*gi-R)FK4A4fJQODBFws7Gc`0c95Rw_w-M30LPw9y&}E^ev-He#G~txF zEe^Qz5>gV!(V0PLw|GPgpZfaR=9}mUM%fc$$^lbkVLAS1$mHxpkHw3wS$WBtgWf3hV{fE^3^sRBmHPY-oBEd}`a>}cKd@sG z@b^n(Kb@hrK z44M=eif{GMS!)hnab%eD5q>*JK%C`ZnBJ$C9>onpKjc`%k+uxkN*Nqkv$QM{bN9*m@fizT@rKr_&2Zk zq%obM+4;t|EB2oT%pg$KIE}4`4r_CPGHk%$;SNWo?fRzk=s&e>ba#4Td{AKPSAb=sVjRDhC{E!{e0mqvZ`bV$#xN+**zBTNQRzVs-waK!fpf8*%4yp3rD{C(txxA&w`68o zu2c5XX=U8Dt^a;q-=^d9p5;yhD_-of7Z*N%Plp3^?RHz6lDo(nS&e>>qsLiXe8p#H z-m-!;U6HIW8U94e*Uv1U(&PNJX`k0%Ww%wnYkuimDanq@aVK7AO@l0W=*gCwR^692 z3z?Us(9|+!9q`rRf3Ge}n}d_QXl2ab>mPl#R18KpIGr>T+q@cgnM!{5oO6$O^x=zg zoW!9d5)Nzk@Cj=0LA0t=W*fa{>ZqXT^5uUS@Xccr)6tiI>s#^qy8EbmxQ|<&t!zAW zy`D?LcTSr(lY$VL{kSmcnUXM%qMY#y9TB;XHHMTp=ed`ZmJH}Lh$h%lZu=yu!$#;h zh>rIF#?_H1l-7g=nHec78gbIS>t8*JE?L=)enm~(XJ*(oHF~BCJ-^IdlS)DbZDbOU zqV{l4#|@+JZBm;qkl&G3YJ&WZwiDso1o<6RqoM@)9VL;MFux-|cF`K^LxuDKFB6=RgtB@^#_yg68BlOzPxRyNBkkfH;cl<-IRcy@>ae zUf#1Sg7|`5FYmpxqVNml16>#HQ4%Dix|g{cz0*t-L=})H??yuJetQ4<^(UUC-L^+b z6htVl+xEPO-kq;mS0dfEou|b^WmN|#`$;@Xf?blxo$TY2pv()gD{aoSV(;lIAb~=v z3(|xt(P?kYJnVPE-Oaya=3x5MF5IMM;8uB+E)Y z=rMm>b=|EGl&8%rT+?1?)r+FMN9<({5khud*x)mn{9_6nS$<pV1y30@55q)BGagQ&)J88}q(Z=i|u8PEu3W*4eBGlYN%b13lf zh~{_cxN-3z$I&g-d#qnpH|liaGgve8-R(~dKDsw;4dCl2=(Myy04AOvIp@{+S0C4a z?#zjwmWJxfWKis#ppVb2%K+Iei0Wpm&!)&Qe)uVPIH{Ue}{uh;ou z)HyR(uHRi!(#>;;70>|F<`^pplh&+M4jbp!dHGzB{!U&rm0EyCvF*xtHy?@&N#bO1 z&V?Xd_Z~4pIxaw?n08U&1E5ct2cZu<+)~yq6bFx3d(B_B9HZ+$OeNxGo4bqS^TF?j z`q_hpP91icS23nWM$#2n_8+&juBd(xM0ktT?@nlHlaBb*b-qf-s?$zZEKahgclpQ> zglNH*ek!78n+A-tCpTI6^UB|3D?#bZ0=pNQtCvPDR>C(fH>Ip`McMe$A!Rj`ZH}$C z&@)ctMH*`%8rA;s(0EXza*va)u+C0=p<4ATeNjwbL#dbr$a2SM>VDf&QyZK~RuWI9 zSr_mk%G z=%g9nuiJ|p)fFf8S#a{>^?4!e|+jdF9B$!{WZLy8s)D>uslnX=Zz zCZz|i%&K2rKjC;RsBpQ)WLHaz$GM?>tdsISzK|Z)k33#t=J$lKcsQp{t0l#XWxVM} zt%|}gbTO419r^%IdRV=!V!J~>3eDWm&(HoVir%2$ruMzi+R^ZciS8+ILqFfAE4z}2 zmZ6_VAxL%#&ciV{i9dWkfaP>F(}pQ5OC^AD7mmd3mJ=jx@hB$W3tpcbSkdE#`60hJ`r zbiR(rR+mTy&KrXYEn6WZU*>tyYE*VzzRZ(o9SPsseC@8rRqQovosK73x2&`&O@mcF zefi>Ya+xS)`DLFdaCP+prxnDi&$icQM zExPIalb%~K`)pdhI;E>3p4hGB=X4X#X)C6j5GPGmP$AtEsV5wVC4@Q*4Ka z+p<8HO7h+X+5%u!pc>-gA+t%#lI0}~GE=VU`oZfvTv0iEoA7H^BuTV# Date: Mon, 28 Oct 2019 10:55:40 -0700 Subject: [PATCH 02/12] Get metadata flags test working --- .../grpcio_tests/tests/unit/_metadata_flags_test.py | 6 +++--- .../tests/unit/framework/common/__init__.py | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py index 47cb26d8693..16f861ed527 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py @@ -25,7 +25,7 @@ import grpc from tests.unit import test_common from tests.unit.framework.common import test_constants import tests.unit.framework.common -from tests.unit.framework.common import listening_socket +from tests.unit.framework.common import bound_socket _UNARY_UNARY = '/test/UnaryUnary' _UNARY_STREAM = '/test/UnaryStream' @@ -123,7 +123,7 @@ class _GenericHandler(grpc.GenericRpcHandler): def create_dummy_channel(): """Creating dummy channels is a workaround for retries""" # _, addr = get_free_loopback_tcp_port() - with listening_socket() as host, port: + with bound_socket() as (host, port): return grpc.insecure_channel('{}:{}'.format(host, port)) @@ -224,7 +224,7 @@ class MetadataFlagsTest(unittest.TestCase): # main thread. So, it need another method to store the # exceptions and raise them again in main thread. unhandled_exceptions = queue.Queue() - with listening_socket() as (host, port): + with bound_socket(listen=False) as (host, port): addr = '{}:{}'.format(host, port) wg = test_common.WaitGroup(len(_ALL_CALL_CASES)) diff --git a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py index 21440430a28..a32ea98d229 100644 --- a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py +++ b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py @@ -16,7 +16,7 @@ import contextlib import socket -def get_socket(bind_address='localhost', sock_options=(socket.SO_REUSEPORT,)): +def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): """Opens a listening socket on an arbitrary port. Useful for reserving a port for a system-under-test. @@ -38,7 +38,8 @@ def get_socket(bind_address='localhost', sock_options=(socket.SO_REUSEPORT,)): for sock_option in _sock_options: sock.setsockopt(socket.SOL_SOCKET, sock_option, 1) sock.bind((bind_address, 0)) - sock.listen(1) + if listen: + sock.listen(1) return bind_address, sock.getsockname()[1], sock except socket.error: continue @@ -46,9 +47,10 @@ def get_socket(bind_address='localhost', sock_options=(socket.SO_REUSEPORT,)): @contextlib.contextmanager -def listening_socket(bind_address='localhost', sock_options=(socket.SO_REUSEPORT,)): +def bound_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): # TODO: Docstring. - host, port, sock = get_socket(bind_address=bind_address, sock_options=sock_options) + # TODO: Just yield address? + host, port, sock = get_socket(bind_address=bind_address, listen=listen, sock_options=sock_options) try: yield host, port finally: From 800e0bb17a504e69f0a5f67a96fd5a30dd2ddf10 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 11:00:56 -0700 Subject: [PATCH 03/12] Migrate compression test --- .../tests/unit/_metadata_flags_test.py | 1 - .../grpcio_tests/tests/unit/_tcp_proxy.py | 31 +++---------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py index 16f861ed527..ff02560d11e 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py @@ -122,7 +122,6 @@ class _GenericHandler(grpc.GenericRpcHandler): def create_dummy_channel(): """Creating dummy channels is a workaround for retries""" - # _, addr = get_free_loopback_tcp_port() with bound_socket() as (host, port): return grpc.insecure_channel('{}:{}'.format(host, port)) diff --git a/src/python/grpcio_tests/tests/unit/_tcp_proxy.py b/src/python/grpcio_tests/tests/unit/_tcp_proxy.py index 5ad0bf8f028..84dc0e2d6cf 100644 --- a/src/python/grpcio_tests/tests/unit/_tcp_proxy.py +++ b/src/python/grpcio_tests/tests/unit/_tcp_proxy.py @@ -27,35 +27,12 @@ import select import socket import threading +from tests.unit.framework.common import get_socket + _TCP_PROXY_BUFFER_SIZE = 1024 _TCP_PROXY_TIMEOUT = datetime.timedelta(milliseconds=500) -def _create_socket_ipv6(bind_address): - listen_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - listen_socket.bind((bind_address, 0, 0, 0)) - return listen_socket - - -def _create_socket_ipv4(bind_address): - listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - listen_socket.bind((bind_address, 0)) - return listen_socket - - -def _init_listen_socket(bind_address): - listen_socket = None - if socket.has_ipv6: - try: - listen_socket = _create_socket_ipv6(bind_address) - except socket.error: - listen_socket = _create_socket_ipv4(bind_address) - else: - listen_socket = _create_socket_ipv4(bind_address) - listen_socket.listen(1) - return listen_socket, listen_socket.getsockname()[1] - - def _init_proxy_socket(gateway_address, gateway_port): proxy_socket = socket.create_connection((gateway_address, gateway_port)) return proxy_socket @@ -87,8 +64,8 @@ class TcpProxy(object): self._thread = threading.Thread(target=self._run_proxy) def start(self): - self._listen_socket, self._port = _init_listen_socket( - self._bind_address) + _, self._port, self._listen_socket = get_socket( + bind_address=self._bind_address) self._proxy_socket = _init_proxy_socket(self._gateway_address, self._gateway_port) self._thread.start() From 09ac5fe57385046befc8dcbf4ba651450ef5814b Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 11:15:57 -0700 Subject: [PATCH 04/12] Fix up reconnect test --- .../grpcio_tests/tests/unit/BUILD.bazel | 3 +- .../tests/unit/_reconnect_test.py | 78 +++++-------------- 2 files changed, 20 insertions(+), 61 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/BUILD.bazel b/src/python/grpcio_tests/tests/unit/BUILD.bazel index 5fb7c1f74d0..60a77dbd4a7 100644 --- a/src/python/grpcio_tests/tests/unit/BUILD.bazel +++ b/src/python/grpcio_tests/tests/unit/BUILD.bazel @@ -26,8 +26,7 @@ GRPCIO_TESTS_UNIT = [ "_metadata_flags_test.py", "_metadata_code_details_test.py", "_metadata_test.py", - # TODO: Issue 16336 - # "_reconnect_test.py", + "_reconnect_test.py", "_resource_exhausted_test.py", "_rpc_test.py", "_signal_handling_test.py", diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py index d4ea126e2b5..3861dee0265 100644 --- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -22,6 +22,7 @@ import grpc from grpc.framework.foundation import logging_pool from tests.unit.framework.common import test_constants +from tests.unit.framework.common import bound_socket _REQUEST = b'\x00\x00\x00' _RESPONSE = b'\x00\x00\x01' @@ -33,44 +34,6 @@ def _handle_unary_unary(unused_request, unused_servicer_context): return _RESPONSE -def _get_reuse_socket_option(): - try: - return socket.SO_REUSEPORT - except AttributeError: - # SO_REUSEPORT is unavailable on Windows, but SO_REUSEADDR - # allows forcibly re-binding to a port - return socket.SO_REUSEADDR - - -def _pick_and_bind_port(sock_opt): - # Reserve a port, when we restart the server we want - # to hold onto the port - port = 0 - for address_family in (socket.AF_INET6, socket.AF_INET): - try: - s = socket.socket(address_family, socket.SOCK_STREAM) - except socket.error: - continue # this address family is unavailable - s.setsockopt(socket.SOL_SOCKET, sock_opt, 1) - try: - s.bind(('localhost', port)) - # for socket.SOCK_STREAM sockets, it is necessary to call - # listen to get the desired behavior. - s.listen(1) - port = s.getsockname()[1] - except socket.error: - # port was not available on the current address family - # try again - port = 0 - break - finally: - s.close() - if s: - return port if port != 0 else _pick_and_bind_port(sock_opt) - else: - return None # no address family was available - - class ReconnectTest(unittest.TestCase): def test_reconnect(self): @@ -79,27 +42,24 @@ class ReconnectTest(unittest.TestCase): 'UnaryUnary': grpc.unary_unary_rpc_method_handler(_handle_unary_unary) }) - sock_opt = _get_reuse_socket_option() - port = _pick_and_bind_port(sock_opt) - self.assertIsNotNone(port) - - server = grpc.server(server_pool, (handler,)) - server.add_insecure_port('[::]:{}'.format(port)) - server.start() - channel = grpc.insecure_channel('localhost:%d' % port) - multi_callable = channel.unary_unary(_UNARY_UNARY) - self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) - server.stop(None) - # By default, the channel connectivity is checked every 5s - # GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change - # this. - time.sleep(5.1) - server = grpc.server(server_pool, (handler,)) - server.add_insecure_port('[::]:{}'.format(port)) - server.start() - self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) - server.stop(None) - channel.close() + with bound_socket() as (_, port): + server = grpc.server(server_pool, (handler,)) + server.add_insecure_port('[::]:{}'.format(port)) + server.start() + channel = grpc.insecure_channel('localhost:%d' % port) + multi_callable = channel.unary_unary(_UNARY_UNARY) + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + # By default, the channel connectivity is checked every 5s + # GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change + # this. + time.sleep(5.1) + server = grpc.server(server_pool, (handler,)) + server.add_insecure_port('[::]:{}'.format(port)) + server.start() + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + channel.close() if __name__ == '__main__': From bf7accb2dbee820c6902ab41c953ebe822706453 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 11:18:48 -0700 Subject: [PATCH 05/12] Remove unused code --- .../tests/unit/_metadata_flags_test.py | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py index ff02560d11e..59fb83708ce 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py @@ -95,31 +95,6 @@ class _GenericHandler(grpc.GenericRpcHandler): return None -# def _create_socket_ipv6(bind_address): -# listen_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) -# listen_socket.bind((bind_address, 0, 0, 0)) -# return listen_socket -# -# -# def _create_socket_ipv4(bind_address): -# listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# listen_socket.bind((bind_address, 0)) -# return listen_socket -# -# -# def get_free_loopback_tcp_port(): -# listen_socket = None -# if socket.has_ipv6: -# try: -# listen_socket = _create_socket_ipv6('') -# except socket.error: -# listen_socket = _create_socket_ipv4('') -# else: -# listen_socket = _create_socket_ipv4('') -# address_tuple = listen_socket.getsockname() -# return listen_socket, "localhost:%s" % (address_tuple[1]) - - def create_dummy_channel(): """Creating dummy channels is a workaround for retries""" with bound_socket() as (host, port): From 349d79cae92d7da4b9a5d9bfdd055eb5fb07c7d3 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 11:46:40 -0700 Subject: [PATCH 06/12] Integrate with asyncio tests --- .../grpcio_tests/tests_aio/unit/BUILD.bazel | 22 +++++++++++++++++++ .../grpcio_tests/tests_aio/unit/test_base.py | 16 +++----------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/python/grpcio_tests/tests_aio/unit/BUILD.bazel b/src/python/grpcio_tests/tests_aio/unit/BUILD.bazel index c6d0a9f7728..877337eb582 100644 --- a/src/python/grpcio_tests/tests_aio/unit/BUILD.bazel +++ b/src/python/grpcio_tests/tests_aio/unit/BUILD.bazel @@ -19,8 +19,27 @@ package( GRPC_ASYNC_TESTS = [ "server_test.py", + "init_test.py", + "channel_test.py", ] +py_library( + name = "test_base", + srcs = ["test_base.py"], + srcs_version = "PY3", +) + +py_library( + name = "sync_server", + srcs = ["sync_server.py"], + deps = [ + "//src/proto/grpc/testing:empty_py_pb2", + "//src/proto/grpc/testing:py_messages_proto", + "//src/proto/grpc/testing:test_py_pb2_grpc", + ], + srcs_version = "PY3", +) + [ py_test( name=test_file_name[:-3], @@ -33,6 +52,9 @@ GRPC_ASYNC_TESTS = [ "//src/proto/grpc/testing:py_messages_proto", "//src/proto/grpc/testing:benchmark_service_py_pb2_grpc", "//src/proto/grpc/testing:benchmark_service_py_pb2", + "//src/python/grpcio_tests/tests/unit/framework/common", + ":test_base", + ":sync_server", "//external:six" ], imports=["../../",], diff --git a/src/python/grpcio_tests/tests_aio/unit/test_base.py b/src/python/grpcio_tests/tests_aio/unit/test_base.py index 0b325523e0f..22c79e0f825 100644 --- a/src/python/grpcio_tests/tests_aio/unit/test_base.py +++ b/src/python/grpcio_tests/tests_aio/unit/test_base.py @@ -22,21 +22,11 @@ import socket from grpc.experimental import aio from tests_aio.unit import sync_server - +from tests.unit.framework.common import get_socket def _get_free_loopback_tcp_port(): - if socket.has_ipv6: - tcp_socket = socket.socket(socket.AF_INET6) - host = "::1" - host_target = "[::1]" - else: - tcp_socket = socket.socket(socket.AF_INET) - host = "127.0.0.1" - host_target = host - tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - tcp_socket.bind((host, 0)) - address_tuple = tcp_socket.getsockname() - return tcp_socket, "%s:%s" % (host_target, address_tuple[1]) + host, port, sock = get_socket(listen=False) + return sock, "{}:{}".format(host, port) class _Server: From a577c75cb1a28af2de074be1d65fc3d7319b1e54 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 11:48:57 -0700 Subject: [PATCH 07/12] Update docstrings --- .../tests/unit/framework/common/__init__.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py index a32ea98d229..70a66a7a864 100644 --- a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py +++ b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2015 gRPC authors. +# Copyright 2019 The gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,12 +17,13 @@ import socket def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): - """Opens a listening socket on an arbitrary port. + """Opens a socket bound to an arbitrary port. Useful for reserving a port for a system-under-test. Args: bind_address: The host to which to bind. + listen: A boolean value indicating whether or not to listen on the socket. sock_options: A sequence of socket options to apply to the socket. Returns: @@ -48,8 +49,20 @@ def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_RE @contextlib.contextmanager def bound_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): - # TODO: Docstring. - # TODO: Just yield address? + """Opens a socket bound to an arbitrary port. + + Useful for reserving a port for a system-under-test. + + Args: + bind_address: The host to which to bind. + listen: A boolean value indicating whether or not to listen on the socket. + sock_options: A sequence of socket options to apply to the socket. + + Yields: + A tuple containing: + - the address to which the socket is bound + - the port to which the socket is bound + """ host, port, sock = get_socket(bind_address=bind_address, listen=listen, sock_options=sock_options) try: yield host, port From 89fba9789272a649b140a140d595a0ec4eda72c2 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 12:17:16 -0700 Subject: [PATCH 08/12] Yapf. Pylint --- .../tests/unit/_metadata_flags_test.py | 3 ++- .../tests/unit/framework/common/__init__.py | 14 ++++++++++---- .../grpcio_tests/tests_aio/unit/test_base.py | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py index 59fb83708ce..c2d2aa7c2e3 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py @@ -229,7 +229,8 @@ class MetadataFlagsTest(unittest.TestCase): # Start the server after the connections are waiting wg.wait() server = test_common.test_server() - server.add_generic_rpc_handlers((_GenericHandler(weakref.proxy(self)),)) + server.add_generic_rpc_handlers((_GenericHandler( + weakref.proxy(self)),)) server.add_insecure_port(addr) server.start() diff --git a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py index 70a66a7a864..79b6a603344 100644 --- a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py +++ b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py @@ -16,7 +16,9 @@ import contextlib import socket -def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): +def get_socket(bind_address='localhost', + listen=True, + sock_options=(socket.SO_REUSEPORT,)): """Opens a socket bound to an arbitrary port. Useful for reserving a port for a system-under-test. @@ -44,11 +46,14 @@ def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_RE return bind_address, sock.getsockname()[1], sock except socket.error: continue - raise RuntimeError("Failed to find to {} with sock_options {}".format(bind_address, sock_options)) + raise RuntimeError("Failed to bind to {} with sock_options {}".format( + bind_address, sock_options)) @contextlib.contextmanager -def bound_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): +def bound_socket(bind_address='localhost', + listen=True, + sock_options=(socket.SO_REUSEPORT,)): """Opens a socket bound to an arbitrary port. Useful for reserving a port for a system-under-test. @@ -63,7 +68,8 @@ def bound_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_ - the address to which the socket is bound - the port to which the socket is bound """ - host, port, sock = get_socket(bind_address=bind_address, listen=listen, sock_options=sock_options) + host, port, sock = get_socket( + bind_address=bind_address, listen=listen, sock_options=sock_options) try: yield host, port finally: diff --git a/src/python/grpcio_tests/tests_aio/unit/test_base.py b/src/python/grpcio_tests/tests_aio/unit/test_base.py index 22c79e0f825..a0078cd7d5c 100644 --- a/src/python/grpcio_tests/tests_aio/unit/test_base.py +++ b/src/python/grpcio_tests/tests_aio/unit/test_base.py @@ -24,6 +24,7 @@ from grpc.experimental import aio from tests_aio.unit import sync_server from tests.unit.framework.common import get_socket + def _get_free_loopback_tcp_port(): host, port, sock = get_socket(listen=False) return sock, "{}:{}".format(host, port) From 90ee052cb837c17c29b11ae83182958bebe0b1e1 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 12:45:03 -0700 Subject: [PATCH 09/12] Attempt to work on kokoro --- .../tests/stress/single_thread.cprof | Bin 122523 -> 0 bytes .../tests/unit/framework/common/__init__.py | 6 +++++- 2 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 src/python/grpcio_tests/tests/stress/single_thread.cprof diff --git a/src/python/grpcio_tests/tests/stress/single_thread.cprof b/src/python/grpcio_tests/tests/stress/single_thread.cprof deleted file mode 100644 index 3ae627d1c7b80c4b0b408adb7e9e285beb3b9656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122523 zcmd4437AyH)jp2G0K>kBD9YvnqB5u`qLOJ4L=g}K1UJ$)Gd-6pGt*;r4=_wzV@#qZ znrQMxvuWJo5=G;dsEKAVpG%auMLRL#ZfE<5OB9Uyf8VNG=ib|OyFoHOzkffEWij{E zIj2sYI(6#Q_Thx?TXs0B)D6EahfHh97FOmO$Bg$2*_QnHF}bEO;~R3#&Dn;6pKHz6 zEl`bFm2I5mHx%%3#p(EazJ5YY={G2?dLZ$>_K&-+djH`~^^)nlvHO;VliKrYQgf~$ z(>%$`<-F$Xq?Ngr>?E}!3*4*yNwc!6CwZ!^VPbo0Ms-Zg7gRRWGHG?Tb@ilXf5oJ> z4sg{vxo*m&Y-@W2y9@$P@~S%v38E zXJ%hvCL-@j?35ZLo)V?`nh`6IVXpOlh5hLdD+GT5^r;&Dr`1 zJxW?0gNX|N>7Qh7G!-jdg+FhporZcf_qwsb)e@G{U>0fcq(X3TtXz2R_MOI&}b&!%X?3K@7&i~Qj%e}ztnKo1-3O0BQ&us)37SzW%Jq``?-k+)*W<6 z-2rut+0_S3Z0mptp4jZSwy&MIcIuS$l!NQCo~I!vrC}vna;;R4nQXnDrb@7e8+w6% zCSFU+%N;j9zcM8mS}kqy)5hYbSD@6&mW*0OJckfZFQ`S6-wbQwzlA=m6R)(P)N$y} zvr>`)qT{+u4moy1{|z*%nhX}IwPN==Sl7vFquQEj$u<_++t?zSoeDg~>o`{G zm~U(LgK@V^(Mv6?;gPK2%_l!~{D7wJDao*gN!`$I%QQBsz;ONmMT^7JnnF6)Mvo=a z3=g5ulF6@vHJ?QMM-#s@a-bDw;e$UHBUW)}+HZr&D5RTIu7#S3ZjRzRvG}npZW?rh z9Sk_RVW$fBXk=SjZ<49BmPQMPbc0n4=w)RZ>^h>k_`Q1wpHl} zBwPASYxeWj$*)!{&c!&f2C6Ni3O>zkGAF}OU7tx{6ZS|+h9c2g^9PEgmSTnd&Ne{R zE`}cI#Cz()hyVD4lXgr=1|4-|H65<^uc8w61YeLXH1F4_rz#)`hRhvOk_i|nrSKK= zIIZk@1VOROS!^wf8HN4CD(ok;_zEBVA9L6rj-~|T8T{9r%QU9jTQSvLMZdfBBckXe ziobN5{L(`U{!=d*wE}-eyEhVqNg$QC?S$s-`nbfyZqeR`c~PRUOM4O9nZ)L3Gn<{} zMOP`_?7BpSVsR$IX3rPU?D;i*VPzsG{wNLwOuWX_Mb{nk3pBgU*om5gCE>)hIn%PD zF~d1#mi(Pd_BXA3^(%LM@JzjAz&$5-C4N=sAc5?3UV}Tm&4OQ$2yTQE8Nx02MTy{* zm@$p#Fk`SshI5PkTUD^XW~=%dwTlB+iS9#CRe$0R5GNDwk>CAu$GvO*T`w66etaUh z<1Sioj)E@s;eDPTF#GTC)O$7)fUALt;QPK*;4P>jA{a0%&g+y`o}8iUnTSG zdl+{(toH#}z*%V>^Bg)7hP%LzI+`HgAjpr#ZTZ6GgWs%|3`iZ{wPQN@;}DJx)QB)x z5FAn3d1d0-eF$&?K9r^-Dc1P;%nF+OYQ9P^jE56Rl+?e72#wv`p+=i6%#fPXddx*1 zVu(n67fB$oNYo=Wu65;oWaQQB!qyBMLO-eFiz

Y>?eY1h7SfE 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 Date: Mon, 28 Oct 2019 15:25:12 -0700 Subject: [PATCH 10/12] Incorporate review comments --- .../tests/unit/_metadata_flags_test.py | 2 +- .../tests/unit/_reconnect_test.py | 36 ++++++++++--------- .../grpcio_tests/tests/unit/test_common.py | 4 +-- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py index c2d2aa7c2e3..efc55ea2ddf 100644 --- a/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py +++ b/src/python/grpcio_tests/tests/unit/_metadata_flags_test.py @@ -228,7 +228,7 @@ class MetadataFlagsTest(unittest.TestCase): # Start the server after the connections are waiting wg.wait() - server = test_common.test_server() + server = test_common.test_server(reuse_port=True) server.add_generic_rpc_handlers((_GenericHandler( weakref.proxy(self)),)) server.add_insecure_port(addr) diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py index 3861dee0265..8d7fd38868b 100644 --- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -42,24 +42,26 @@ class ReconnectTest(unittest.TestCase): 'UnaryUnary': grpc.unary_unary_rpc_method_handler(_handle_unary_unary) }) - with bound_socket() as (_, port): - server = grpc.server(server_pool, (handler,)) - server.add_insecure_port('[::]:{}'.format(port)) + options=(('grpc.so_reuseport', 0),) + with bound_socket() as (host, port): + addr = '{}:{}'.format(host, port) + server = grpc.server(server_pool, (handler,), options=options) + server.add_insecure_port(addr) server.start() - channel = grpc.insecure_channel('localhost:%d' % port) - multi_callable = channel.unary_unary(_UNARY_UNARY) - self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) - server.stop(None) - # By default, the channel connectivity is checked every 5s - # GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change - # this. - time.sleep(5.1) - server = grpc.server(server_pool, (handler,)) - server.add_insecure_port('[::]:{}'.format(port)) - server.start() - self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) - server.stop(None) - channel.close() + channel = grpc.insecure_channel(addr) + multi_callable = channel.unary_unary(_UNARY_UNARY) + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + # By default, the channel connectivity is checked every 5s + # GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS can be set to change + # this. + time.sleep(5.1) + server = grpc.server(server_pool, (handler,), options=options) + server.add_insecure_port(addr) + server.start() + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + channel.close() if __name__ == '__main__': diff --git a/src/python/grpcio_tests/tests/unit/test_common.py b/src/python/grpcio_tests/tests/unit/test_common.py index bc3b24862dc..305781bd533 100644 --- a/src/python/grpcio_tests/tests/unit/test_common.py +++ b/src/python/grpcio_tests/tests/unit/test_common.py @@ -100,14 +100,14 @@ def test_secure_channel(target, channel_credentials, server_host_override): return channel -def test_server(max_workers=10): +def test_server(max_workers=10, reuse_port=False): """Creates an insecure grpc server. These servers have SO_REUSEPORT disabled to prevent cross-talk. """ return grpc.server( futures.ThreadPoolExecutor(max_workers=max_workers), - options=(('grpc.so_reuseport', 0),)) + options=(('grpc.so_reuseport', int(reuse_port)),)) class WaitGroup(object): From 9b058aa157c4905d61d203289d8ab8943cad3bf6 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 28 Oct 2019 15:50:39 -0700 Subject: [PATCH 11/12] =?UTF-8?q?=E5=BF=83=E3=82=88=E3=80=82=E5=BF=83?= =?UTF-8?q?=E3=82=88=E3=80=82=E3=81=93=E3=81=93=E3=81=AF=E3=80=81=E6=82=AA?= =?UTF-8?q?=E3=81=84=E6=89=80=E3=82=88=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/python/grpcio_tests/tests/unit/_reconnect_test.py | 2 +- src/python/grpcio_tests/tests/unit/framework/common/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py index 8d7fd38868b..b19a5b5d76f 100644 --- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -42,7 +42,7 @@ class ReconnectTest(unittest.TestCase): 'UnaryUnary': grpc.unary_unary_rpc_method_handler(_handle_unary_unary) }) - options=(('grpc.so_reuseport', 0),) + options=(('grpc.so_reuseport', 1),) with bound_socket() as (host, port): addr = '{}:{}'.format(host, port) server = grpc.server(server_pool, (handler,), options=options) diff --git a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py index e1979c96b09..488c712c704 100644 --- a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py +++ b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py @@ -15,7 +15,6 @@ import contextlib import socket - def get_socket(bind_address='localhost', listen=True, sock_options=(socket.SO_REUSEPORT,)): @@ -49,6 +48,7 @@ def get_socket(bind_address='localhost', sock.listen(1) return bind_address, sock.getsockname()[1], sock except socket.error: + sock.close() continue raise RuntimeError("Failed to bind to {} with sock_options {}".format( bind_address, sock_options)) From 7bf58e82fdf395c1151e88c65e2a345d5b1e0233 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Wed, 6 Nov 2019 11:16:50 -0800 Subject: [PATCH 12/12] (hopefully) fix Windows --- src/python/grpcio_tests/tests/unit/_reconnect_test.py | 2 +- .../tests/unit/framework/common/__init__.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py index b19a5b5d76f..0d97f9d735b 100644 --- a/src/python/grpcio_tests/tests/unit/_reconnect_test.py +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -42,7 +42,7 @@ class ReconnectTest(unittest.TestCase): 'UnaryUnary': grpc.unary_unary_rpc_method_handler(_handle_unary_unary) }) - options=(('grpc.so_reuseport', 1),) + options = (('grpc.so_reuseport', 1),) with bound_socket() as (host, port): addr = '{}:{}'.format(host, port) server = grpc.server(server_pool, (handler,), options=options) diff --git a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py index 488c712c704..c1ac76248ed 100644 --- a/src/python/grpcio_tests/tests/unit/framework/common/__init__.py +++ b/src/python/grpcio_tests/tests/unit/framework/common/__init__.py @@ -13,11 +13,15 @@ # limitations under the License. import contextlib +import os import socket +_DEFAULT_SOCK_OPTION = socket.SO_REUSEADDR if os.name == 'nt' else socket.SO_REUSEPORT + + def get_socket(bind_address='localhost', listen=True, - sock_options=(socket.SO_REUSEPORT,)): + sock_options=(_DEFAULT_SOCK_OPTION,)): """Opens a socket bound to an arbitrary port. Useful for reserving a port for a system-under-test. @@ -37,7 +41,7 @@ def get_socket(bind_address='localhost', if socket.has_ipv6: address_families = (socket.AF_INET6, socket.AF_INET) else: - address_families = (socket.AF_INET) + address_families = (socket.AF_INET) for address_family in address_families: try: sock = socket.socket(address_family, socket.SOCK_STREAM) @@ -57,7 +61,7 @@ def get_socket(bind_address='localhost', @contextlib.contextmanager def bound_socket(bind_address='localhost', listen=True, - sock_options=(socket.SO_REUSEPORT,)): + sock_options=(_DEFAULT_SOCK_OPTION,)): """Opens a socket bound to an arbitrary port. Useful for reserving a port for a system-under-test.