12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987 |
- // Copyright 2017 gRPC authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- // TODO(roth): Split this file up into a common test framework and a set
- // of test files that use that framework. Need to figure out the best
- // way to split up the tests. One option would be to split it up by xDS
- // resource type; another approach would be to have all of the "core"
- // xDS functionality in one file and then move specific features to
- // their own files (e.g., mTLS security, fault injection, circuit
- // breaking, etc).
- #include <deque>
- #include <memory>
- #include <mutex>
- #include <numeric>
- #include <set>
- #include <sstream>
- #include <string>
- #include <thread>
- #include <vector>
- #include <gmock/gmock.h>
- #include <gtest/gtest.h>
- #include "absl/functional/bind_front.h"
- #include "absl/memory/memory.h"
- #include "absl/strings/match.h"
- #include "absl/strings/str_cat.h"
- #include "absl/strings/str_format.h"
- #include "absl/strings/str_join.h"
- #include "absl/strings/str_replace.h"
- #include "absl/types/optional.h"
- #include <grpc/grpc.h>
- #include <grpc/grpc_security.h>
- #include <grpc/support/alloc.h>
- #include <grpc/support/log.h>
- #include <grpc/support/time.h>
- #include <grpcpp/channel.h>
- #include <grpcpp/client_context.h>
- #include <grpcpp/create_channel.h>
- #include <grpcpp/security/tls_certificate_provider.h>
- #include <grpcpp/server.h>
- #include <grpcpp/server_builder.h>
- #include <grpcpp/xds_server_builder.h>
- #include "src/core/ext/filters/client_channel/backup_poller.h"
- #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_args.h"
- #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
- #include "src/core/ext/xds/certificate_provider_registry.h"
- #include "src/core/ext/xds/xds_api.h"
- #include "src/core/ext/xds/xds_channel_args.h"
- #include "src/core/ext/xds/xds_client.h"
- #include "src/core/ext/xds/xds_listener.h"
- #include "src/core/lib/address_utils/parse_address.h"
- #include "src/core/lib/channel/channel_args.h"
- #include "src/core/lib/gpr/env.h"
- #include "src/core/lib/gpr/string.h"
- #include "src/core/lib/gpr/time_precise.h"
- #include "src/core/lib/gpr/tmpfile.h"
- #include "src/core/lib/gprpp/ref_counted_ptr.h"
- #include "src/core/lib/gprpp/sync.h"
- #include "src/core/lib/gprpp/time.h"
- #include "src/core/lib/gprpp/time_util.h"
- #include "src/core/lib/iomgr/load_file.h"
- #include "src/core/lib/iomgr/sockaddr.h"
- #include "src/core/lib/resolver/server_address.h"
- #include "src/core/lib/security/credentials/fake/fake_credentials.h"
- #include "src/cpp/client/secure_credentials.h"
- #include "src/cpp/server/secure_server_credentials.h"
- #include "src/proto/grpc/testing/echo.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/ads_for_test.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/cds_for_test.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/eds_for_test.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/lds_rds_for_test.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/lrs_for_test.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/ads.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/aggregate_cluster.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/discovery.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/fault.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/listener.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/lrs.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/route.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/router.grpc.pb.h"
- #include "src/proto/grpc/testing/xds/v3/tls.grpc.pb.h"
- #include "test/core/util/port.h"
- #include "test/core/util/resolve_localhost_ip46.h"
- #include "test/core/util/test_config.h"
- #include "test/cpp/end2end/counted_service.h"
- #include "test/cpp/end2end/test_service_impl.h"
- #include "test/cpp/end2end/xds/xds_server.h"
- #include "test/cpp/util/test_config.h"
- #include "test/cpp/util/tls_test_utils.h"
- #ifndef DISABLED_XDS_PROTO_IN_CC
- #include "src/cpp/server/csds/csds.h"
- #include "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h"
- #endif // DISABLED_XDS_PROTO_IN_CC
- namespace grpc {
- namespace testing {
- namespace {
- using std::chrono::system_clock;
- #ifndef DISABLED_XDS_PROTO_IN_CC
- using ::envoy::admin::v3::ClientResourceStatus;
- #endif // DISABLED_XDS_PROTO_IN_CC
- using ::envoy::config::cluster::v3::CircuitBreakers;
- using ::envoy::config::cluster::v3::Cluster;
- using ::envoy::config::cluster::v3::CustomClusterType;
- using ::envoy::config::cluster::v3::RoutingPriority;
- using ::envoy::config::endpoint::v3::ClusterLoadAssignment;
- using ::envoy::config::endpoint::v3::HealthStatus;
- using ::envoy::config::listener::v3::FilterChainMatch;
- using ::envoy::config::listener::v3::Listener;
- using ::envoy::config::rbac::v3::Policy;
- using ::envoy::config::rbac::v3::RBAC_Action;
- using ::envoy::config::rbac::v3::RBAC_Action_ALLOW;
- using ::envoy::config::rbac::v3::RBAC_Action_DENY;
- using ::envoy::config::rbac::v3::RBAC_Action_LOG;
- using ::envoy::config::route::v3::RouteConfiguration;
- using ::envoy::extensions::clusters::aggregate::v3::ClusterConfig;
- using ::envoy::extensions::filters::http::fault::v3::HTTPFault;
- using ::envoy::extensions::filters::http::rbac::v3::RBAC;
- using ::envoy::extensions::filters::http::rbac::v3::RBACPerRoute;
- using ::envoy::extensions::filters::network::http_connection_manager::v3::
- HttpConnectionManager;
- using ::envoy::extensions::filters::network::http_connection_manager::v3::
- HttpFilter;
- using ::envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext;
- using ::envoy::extensions::transport_sockets::tls::v3::UpstreamTlsContext;
- using ::envoy::type::matcher::v3::StringMatcher;
- using ::envoy::type::v3::FractionalPercent;
- using ClientStats = LrsServiceImpl::ClientStats;
- using ::grpc::experimental::ExternalCertificateVerifier;
- using ::grpc::experimental::IdentityKeyCertPair;
- using ::grpc::experimental::StaticDataCertificateProvider;
- constexpr char kDefaultLocalityRegion[] = "xds_default_locality_region";
- constexpr char kDefaultLocalityZone[] = "xds_default_locality_zone";
- constexpr char kLbDropType[] = "lb";
- constexpr char kThrottleDropType[] = "throttle";
- constexpr char kServerName[] = "server.example.com";
- constexpr char kDefaultRouteConfigurationName[] = "route_config_name";
- constexpr char kDefaultServerRouteConfigurationName[] =
- "default_server_route_config_name";
- constexpr char kDefaultClusterName[] = "cluster_name";
- constexpr char kDefaultEdsServiceName[] = "eds_service_name";
- constexpr int kDefaultLocalityWeight = 3;
- constexpr int kDefaultLocalityPriority = 0;
- constexpr char kRequestMessage[] = "Live long and prosper.";
- constexpr char kCaCertPath[] = "src/core/tsi/test_creds/ca.pem";
- constexpr char kServerCertPath[] = "src/core/tsi/test_creds/server1.pem";
- constexpr char kServerKeyPath[] = "src/core/tsi/test_creds/server1.key";
- constexpr char kClientCertPath[] = "src/core/tsi/test_creds/client.pem";
- constexpr char kClientKeyPath[] = "src/core/tsi/test_creds/client.key";
- constexpr char kBadClientCertPath[] = "src/core/tsi/test_creds/badclient.pem";
- constexpr char kBadClientKeyPath[] = "src/core/tsi/test_creds/badclient.key";
- template <typename RpcService>
- class BackendServiceImpl
- : public CountedService<TestMultipleServiceImpl<RpcService>> {
- public:
- BackendServiceImpl() {}
- Status Echo(ServerContext* context, const EchoRequest* request,
- EchoResponse* response) override {
- auto peer_identity = context->auth_context()->GetPeerIdentity();
- CountedService<TestMultipleServiceImpl<RpcService>>::IncreaseRequestCount();
- const auto status =
- TestMultipleServiceImpl<RpcService>::Echo(context, request, response);
- CountedService<
- TestMultipleServiceImpl<RpcService>>::IncreaseResponseCount();
- {
- grpc_core::MutexLock lock(&mu_);
- clients_.insert(context->peer());
- last_peer_identity_.clear();
- for (const auto& entry : peer_identity) {
- last_peer_identity_.emplace_back(entry.data(), entry.size());
- }
- }
- return status;
- }
- Status Echo1(ServerContext* context, const EchoRequest* request,
- EchoResponse* response) override {
- return Echo(context, request, response);
- }
- Status Echo2(ServerContext* context, const EchoRequest* request,
- EchoResponse* response) override {
- return Echo(context, request, response);
- }
- void Start() {}
- void Shutdown() {}
- std::set<std::string> clients() {
- grpc_core::MutexLock lock(&mu_);
- return clients_;
- }
- const std::vector<std::string>& last_peer_identity() {
- grpc_core::MutexLock lock(&mu_);
- return last_peer_identity_;
- }
- private:
- grpc_core::Mutex mu_;
- std::set<std::string> clients_ ABSL_GUARDED_BY(mu_);
- std::vector<std::string> last_peer_identity_ ABSL_GUARDED_BY(mu_);
- };
- class TestType {
- public:
- enum FilterConfigSetup {
- // Set the fault injection filter directly from LDS
- kHTTPConnectionManagerOriginal,
- // Enable the fault injection filter in LDS, but override the filter config
- // in route.
- kRouteOverride,
- };
- enum BootstrapSource {
- kBootstrapFromChannelArg,
- kBootstrapFromFile,
- kBootstrapFromEnvVar,
- };
- TestType& set_enable_load_reporting() {
- enable_load_reporting_ = true;
- return *this;
- }
- TestType& set_enable_rds_testing() {
- enable_rds_testing_ = true;
- return *this;
- }
- TestType& set_use_v2() {
- use_v2_ = true;
- return *this;
- }
- TestType& set_use_xds_credentials() {
- use_xds_credentials_ = true;
- return *this;
- }
- TestType& set_use_csds_streaming() {
- use_csds_streaming_ = true;
- return *this;
- }
- TestType& set_filter_config_setup(FilterConfigSetup setup) {
- filter_config_setup_ = setup;
- return *this;
- }
- TestType& set_bootstrap_source(BootstrapSource bootstrap_source) {
- bootstrap_source_ = bootstrap_source;
- return *this;
- }
- TestType& set_rbac_action(RBAC_Action action) {
- rbac_action_ = action;
- return *this;
- }
- bool enable_load_reporting() const { return enable_load_reporting_; }
- bool enable_rds_testing() const { return enable_rds_testing_; }
- bool use_v2() const { return use_v2_; }
- bool use_xds_credentials() const { return use_xds_credentials_; }
- bool use_csds_streaming() const { return use_csds_streaming_; }
- FilterConfigSetup filter_config_setup() const { return filter_config_setup_; }
- BootstrapSource bootstrap_source() const { return bootstrap_source_; }
- RBAC_Action rbac_action() const { return rbac_action_; }
- std::string AsString() const {
- std::string retval = use_v2_ ? "V2" : "V3";
- if (enable_load_reporting_) retval += "WithLoadReporting";
- if (enable_rds_testing_) retval += "Rds";
- if (use_xds_credentials_) retval += "XdsCreds";
- if (use_csds_streaming_) retval += "CsdsStreaming";
- if (filter_config_setup_ == kRouteOverride) {
- retval += "FilterPerRouteOverride";
- }
- if (bootstrap_source_ == kBootstrapFromFile) {
- retval += "BootstrapFromFile";
- } else if (bootstrap_source_ == kBootstrapFromEnvVar) {
- retval += "BootstrapFromEnvVar";
- }
- if (rbac_action_ == RBAC_Action_ALLOW) {
- retval += "RbacAllow";
- } else if (rbac_action_ == RBAC_Action_DENY) {
- retval += "RbacDeny";
- }
- return retval;
- }
- private:
- bool enable_load_reporting_ = false;
- bool enable_rds_testing_ = false;
- bool use_v2_ = false;
- bool use_xds_credentials_ = false;
- bool use_csds_streaming_ = false;
- FilterConfigSetup filter_config_setup_ = kHTTPConnectionManagerOriginal;
- BootstrapSource bootstrap_source_ = kBootstrapFromChannelArg;
- RBAC_Action rbac_action_ = RBAC_Action_LOG;
- };
- std::string ReadFile(const char* file_path) {
- grpc_slice slice;
- GPR_ASSERT(
- GRPC_LOG_IF_ERROR("load_file", grpc_load_file(file_path, 0, &slice)));
- std::string file_contents(grpc_core::StringViewFromSlice(slice));
- grpc_slice_unref(slice);
- return file_contents;
- }
- grpc_core::PemKeyCertPairList ReadTlsIdentityPair(const char* key_path,
- const char* cert_path) {
- return grpc_core::PemKeyCertPairList{
- grpc_core::PemKeyCertPair(ReadFile(key_path), ReadFile(cert_path))};
- }
- // Based on StaticDataCertificateProvider, but provides alternate certificates
- // if the certificate name is not empty.
- class FakeCertificateProvider final : public grpc_tls_certificate_provider {
- public:
- struct CertData {
- std::string root_certificate;
- grpc_core::PemKeyCertPairList identity_key_cert_pairs;
- };
- using CertDataMap = std::map<std::string /*cert_name */, CertData>;
- explicit FakeCertificateProvider(CertDataMap cert_data_map)
- : distributor_(
- grpc_core::MakeRefCounted<grpc_tls_certificate_distributor>()),
- cert_data_map_(std::move(cert_data_map)) {
- distributor_->SetWatchStatusCallback([this](std::string cert_name,
- bool root_being_watched,
- bool identity_being_watched) {
- if (!root_being_watched && !identity_being_watched) return;
- auto it = cert_data_map_.find(cert_name);
- if (it == cert_data_map_.end()) {
- grpc_error_handle error =
- GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
- "No certificates available for cert_name \"", cert_name, "\""));
- distributor_->SetErrorForCert(cert_name, GRPC_ERROR_REF(error),
- GRPC_ERROR_REF(error));
- GRPC_ERROR_UNREF(error);
- } else {
- absl::optional<std::string> root_certificate;
- absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
- if (root_being_watched) {
- root_certificate = it->second.root_certificate;
- }
- if (identity_being_watched) {
- pem_key_cert_pairs = it->second.identity_key_cert_pairs;
- }
- distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
- std::move(pem_key_cert_pairs));
- }
- });
- }
- ~FakeCertificateProvider() override {
- distributor_->SetWatchStatusCallback(nullptr);
- }
- grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor()
- const override {
- return distributor_;
- }
- private:
- grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
- CertDataMap cert_data_map_;
- };
- class FakeCertificateProviderFactory
- : public grpc_core::CertificateProviderFactory {
- public:
- class Config : public grpc_core::CertificateProviderFactory::Config {
- public:
- explicit Config(const char* name) : name_(name) {}
- const char* name() const override { return name_; }
- std::string ToString() const override { return "{}"; }
- private:
- const char* name_;
- };
- FakeCertificateProviderFactory(
- const char* name, FakeCertificateProvider::CertDataMap** cert_data_map)
- : name_(name), cert_data_map_(cert_data_map) {
- GPR_ASSERT(cert_data_map != nullptr);
- }
- const char* name() const override { return name_; }
- grpc_core::RefCountedPtr<grpc_core::CertificateProviderFactory::Config>
- CreateCertificateProviderConfig(const grpc_core::Json& /*config_json*/,
- grpc_error_handle* /*error*/) override {
- return grpc_core::MakeRefCounted<Config>(name_);
- }
- grpc_core::RefCountedPtr<grpc_tls_certificate_provider>
- CreateCertificateProvider(
- grpc_core::RefCountedPtr<grpc_core::CertificateProviderFactory::Config>
- /*config*/) override {
- if (*cert_data_map_ == nullptr) return nullptr;
- return grpc_core::MakeRefCounted<FakeCertificateProvider>(**cert_data_map_);
- }
- private:
- const char* name_;
- FakeCertificateProvider::CertDataMap** cert_data_map_;
- };
- // Global variables for each provider.
- FakeCertificateProvider::CertDataMap* g_fake1_cert_data_map = nullptr;
- FakeCertificateProvider::CertDataMap* g_fake2_cert_data_map = nullptr;
- std::shared_ptr<ChannelCredentials> CreateTlsFallbackCredentials() {
- IdentityKeyCertPair key_cert_pair;
- key_cert_pair.private_key = ReadFile(kServerKeyPath);
- key_cert_pair.certificate_chain = ReadFile(kServerCertPath);
- std::vector<IdentityKeyCertPair> identity_key_cert_pairs;
- identity_key_cert_pairs.emplace_back(key_cert_pair);
- auto certificate_provider = std::make_shared<StaticDataCertificateProvider>(
- ReadFile(kCaCertPath), identity_key_cert_pairs);
- grpc::experimental::TlsChannelCredentialsOptions options;
- options.set_certificate_provider(std::move(certificate_provider));
- options.watch_root_certs();
- options.watch_identity_key_cert_pairs();
- auto verifier =
- ExternalCertificateVerifier::Create<SyncCertificateVerifier>(true);
- options.set_certificate_verifier(std::move(verifier));
- options.set_verify_server_certs(true);
- options.set_check_call_host(false);
- auto channel_creds = grpc::experimental::TlsCredentials(options);
- GPR_ASSERT(channel_creds.get() != nullptr);
- return channel_creds;
- }
- // A No-op HTTP filter used for verifying parsing logic.
- class NoOpHttpFilter : public grpc_core::XdsHttpFilterImpl {
- public:
- NoOpHttpFilter(std::string name, bool supported_on_clients,
- bool supported_on_servers, bool is_terminal_filter)
- : name_(std::move(name)),
- supported_on_clients_(supported_on_clients),
- supported_on_servers_(supported_on_servers),
- is_terminal_filter_(is_terminal_filter) {}
- void PopulateSymtab(upb_DefPool* /* symtab */) const override {}
- absl::StatusOr<grpc_core::XdsHttpFilterImpl::FilterConfig>
- GenerateFilterConfig(upb_StringView /* serialized_filter_config */,
- upb_Arena* /* arena */) const override {
- return grpc_core::XdsHttpFilterImpl::FilterConfig{name_, grpc_core::Json()};
- }
- absl::StatusOr<grpc_core::XdsHttpFilterImpl::FilterConfig>
- GenerateFilterConfigOverride(upb_StringView /*serialized_filter_config*/,
- upb_Arena* /*arena*/) const override {
- return grpc_core::XdsHttpFilterImpl::FilterConfig{name_, grpc_core::Json()};
- }
- const grpc_channel_filter* channel_filter() const override { return nullptr; }
- absl::StatusOr<grpc_core::XdsHttpFilterImpl::ServiceConfigJsonEntry>
- GenerateServiceConfig(
- const FilterConfig& /*hcm_filter_config*/,
- const FilterConfig* /*filter_config_override*/) const override {
- return grpc_core::XdsHttpFilterImpl::ServiceConfigJsonEntry{name_, ""};
- }
- bool IsSupportedOnClients() const override { return supported_on_clients_; }
- bool IsSupportedOnServers() const override { return supported_on_servers_; }
- bool IsTerminalFilter() const override { return is_terminal_filter_; }
- private:
- const std::string name_;
- const bool supported_on_clients_;
- const bool supported_on_servers_;
- const bool is_terminal_filter_;
- };
- // There is slight difference between time fetched by GPR and by C++ system
- // clock API. It's unclear if they are using the same syscall, but we do know
- // GPR round the number at millisecond-level. This creates a 1ms difference,
- // which could cause flake.
- grpc_core::Timestamp NowFromCycleCounter() {
- return grpc_core::Timestamp::FromTimespecRoundDown(
- gpr_now(GPR_CLOCK_MONOTONIC));
- }
- // Returns the number of RPCs needed to pass error_tolerance at 99.99994%
- // chance. Rolling dices in drop/fault-injection generates a binomial
- // distribution (if our code is not horribly wrong). Let's make "n" the number
- // of samples, "p" the probability. If we have np>5 & n(1-p)>5, we can
- // approximately treat the binomial distribution as a normal distribution.
- //
- // For normal distribution, we can easily look up how many standard deviation we
- // need to reach 99.995%. Based on Wiki's table
- // https://en.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7_rule, we need 5.00
- // sigma (standard deviation) to cover the probability area of 99.99994%. In
- // another word, for a sample with size "n" probability "p" error-tolerance "k",
- // we want the error always land within 5.00 sigma. The sigma of binominal
- // distribution and be computed as sqrt(np(1-p)). Hence, we have the equation:
- //
- // kn <= 5.00 * sqrt(np(1-p))
- size_t ComputeIdealNumRpcs(double p, double error_tolerance) {
- GPR_ASSERT(p >= 0 && p <= 1);
- size_t num_rpcs =
- ceil(p * (1 - p) * 5.00 * 5.00 / error_tolerance / error_tolerance);
- gpr_log(GPR_INFO,
- "Sending %" PRIuPTR " RPCs for percentage=%.3f error_tolerance=%.3f",
- num_rpcs, p, error_tolerance);
- return num_rpcs;
- }
- // Channel arg pointer vtable for storing xDS channel args in the parent
- // channel's channel args.
- void* ChannelArgsArgCopy(void* p) {
- auto* args = static_cast<grpc_channel_args*>(p);
- return grpc_channel_args_copy(args);
- }
- void ChannelArgsArgDestroy(void* p) {
- auto* args = static_cast<grpc_channel_args*>(p);
- grpc_channel_args_destroy(args);
- }
- int ChannelArgsArgCmp(void* a, void* b) {
- auto* args_a = static_cast<grpc_channel_args*>(a);
- auto* args_b = static_cast<grpc_channel_args*>(b);
- return grpc_channel_args_compare(args_a, args_b);
- }
- const grpc_arg_pointer_vtable kChannelArgsArgVtable = {
- ChannelArgsArgCopy, ChannelArgsArgDestroy, ChannelArgsArgCmp};
- class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
- protected:
- // TODO(roth): In a subsequent PR, move BalancerServerThread definition
- // here to avoid the need for this forward declaration.
- class BalancerServerThread;
- class BootstrapBuilder {
- public:
- BootstrapBuilder() {}
- BootstrapBuilder& SetV2() {
- v2_ = true;
- return *this;
- }
- BootstrapBuilder& SetDefaultServer(const std::string& server) {
- top_server_ = server;
- return *this;
- }
- BootstrapBuilder& SetClientDefaultListenerResourceNameTemplate(
- const std::string& client_default_listener_resource_name_template) {
- client_default_listener_resource_name_template_ =
- client_default_listener_resource_name_template;
- return *this;
- }
- BootstrapBuilder& AddCertificateProviderPlugin(
- const std::string& key, const std::string& name,
- const std::string& plugin_config = "") {
- plugins_[key] = {name, plugin_config};
- return *this;
- }
- BootstrapBuilder& AddAuthority(
- const std::string& authority, const std::string& servers = "",
- const std::string& client_listener_resource_name_template = "") {
- authorities_[authority] = {servers,
- client_listener_resource_name_template};
- return *this;
- }
- BootstrapBuilder& SetServerListenerResourceNameTemplate(
- const std::string& server_listener_resource_name_template = "") {
- server_listener_resource_name_template_ =
- server_listener_resource_name_template;
- return *this;
- }
- std::string Build() {
- std::vector<std::string> fields;
- fields.push_back(MakeXdsServersText(top_server_));
- if (!client_default_listener_resource_name_template_.empty()) {
- fields.push_back(absl::StrCat(
- " \"client_default_listener_resource_name_template\": \"",
- client_default_listener_resource_name_template_, "\""));
- }
- fields.push_back(MakeNodeText());
- if (!server_listener_resource_name_template_.empty()) {
- fields.push_back(
- absl::StrCat(" \"server_listener_resource_name_template\": \"",
- server_listener_resource_name_template_, "\""));
- }
- fields.push_back(MakeCertificateProviderText());
- fields.push_back(MakeAuthorityText());
- return absl::StrCat("{", absl::StrJoin(fields, ",\n"), "}");
- }
- private:
- struct PluginInfo {
- std::string name;
- std::string plugin_config;
- };
- struct AuthorityInfo {
- std::string server;
- std::string client_listener_resource_name_template;
- };
- std::string MakeXdsServersText(absl::string_view server_uri) {
- constexpr char kXdsServerTemplate[] =
- " \"xds_servers\": [\n"
- " {\n"
- " \"server_uri\": \"<SERVER_URI>\",\n"
- " \"channel_creds\": [\n"
- " {\n"
- " \"type\": \"fake\"\n"
- " }\n"
- " ],\n"
- " \"server_features\": [<SERVER_FEATURES>]\n"
- " }\n"
- " ]";
- return absl::StrReplaceAll(
- kXdsServerTemplate,
- {{"<SERVER_URI>", server_uri},
- {"<SERVER_FEATURES>", (v2_ ? "" : "\"xds_v3\"")}});
- }
- std::string MakeNodeText() {
- constexpr char kXdsNode[] =
- " \"node\": {\n"
- " \"id\": \"xds_end2end_test\",\n"
- " \"cluster\": \"test\",\n"
- " \"metadata\": {\n"
- " \"foo\": \"bar\"\n"
- " },\n"
- " \"locality\": {\n"
- " \"region\": \"corp\",\n"
- " \"zone\": \"svl\",\n"
- " \"sub_zone\": \"mp3\"\n"
- " }\n"
- " }";
- return kXdsNode;
- }
- std::string MakeCertificateProviderText() {
- std::vector<std::string> entries;
- for (const auto& p : plugins_) {
- const std::string& key = p.first;
- const PluginInfo& plugin_info = p.second;
- std::vector<std::string> fields;
- fields.push_back(absl::StrFormat(" \"%s\": {", key));
- if (!plugin_info.plugin_config.empty()) {
- fields.push_back(absl::StrFormat(" \"plugin_name\": \"%s\",",
- plugin_info.name));
- fields.push_back(absl::StrCat(
- " \"config\": {\n", plugin_info.plugin_config, "\n }"));
- } else {
- fields.push_back(absl::StrFormat(" \"plugin_name\": \"%s\"",
- plugin_info.name));
- }
- fields.push_back(" }");
- entries.push_back(absl::StrJoin(fields, "\n"));
- }
- return absl::StrCat(" \"certificate_providers\": {\n",
- absl::StrJoin(entries, ",\n"), " \n}");
- }
- std::string MakeAuthorityText() {
- std::vector<std::string> entries;
- for (const auto& p : authorities_) {
- const std::string& name = p.first;
- const AuthorityInfo& authority_info = p.second;
- std::vector<std::string> fields = {
- MakeXdsServersText(authority_info.server)};
- if (!authority_info.client_listener_resource_name_template.empty()) {
- fields.push_back(absl::StrCat(
- "\"client_listener_resource_name_template\": \"",
- authority_info.client_listener_resource_name_template, "\""));
- }
- entries.push_back(absl::StrCat(absl::StrFormat("\"%s\": {\n ", name),
- absl::StrJoin(fields, ",\n"), "\n}"));
- }
- return absl::StrCat("\"authorities\": {\n", absl::StrJoin(entries, ",\n"),
- "\n}");
- }
- bool v2_ = false;
- std::string top_server_;
- std::string client_default_listener_resource_name_template_;
- std::map<std::string /*key*/, PluginInfo> plugins_;
- std::map<std::string /*authority_name*/, AuthorityInfo> authorities_;
- std::string server_listener_resource_name_template_ =
- "grpc/server?xds.resource.listening_address=%s";
- };
- // TODO(roth): We currently set the number of backends on a per-test-suite
- // basis, not a per-test-case basis. However, not every individual test
- // case in a given test suite uses the same number of backends, so we wind
- // up having to set the numbers for the test suite to the max number needed
- // by any one test case in that test suite. This results in starting more
- // servers (and using more ports) than we actually need. When we have
- // time, change each test to directly start the number of backends
- // that it needs, so that we aren't wasting resources.
- explicit XdsEnd2endTest(size_t num_backends,
- int client_load_reporting_interval_seconds = 100,
- int xds_resource_does_not_exist_timeout_ms = 0,
- bool use_xds_enabled_server = false)
- : num_backends_(num_backends),
- client_load_reporting_interval_seconds_(
- client_load_reporting_interval_seconds),
- xds_resource_does_not_exist_timeout_ms_(
- xds_resource_does_not_exist_timeout_ms),
- use_xds_enabled_server_(use_xds_enabled_server) {
- bool localhost_resolves_to_ipv4 = false;
- bool localhost_resolves_to_ipv6 = false;
- grpc_core::LocalhostResolves(&localhost_resolves_to_ipv4,
- &localhost_resolves_to_ipv6);
- ipv6_only_ = !localhost_resolves_to_ipv4 && localhost_resolves_to_ipv6;
- // Initialize default xDS resources.
- // Construct LDS resource.
- default_listener_.set_name(kServerName);
- HttpConnectionManager http_connection_manager;
- if (!GetParam().use_v2()) {
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("router");
- filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- }
- default_listener_.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- // Construct RDS resource.
- default_route_config_.set_name(kDefaultRouteConfigurationName);
- auto* virtual_host = default_route_config_.add_virtual_hosts();
- virtual_host->add_domains("*");
- auto* route = virtual_host->add_routes();
- route->mutable_match()->set_prefix("");
- route->mutable_route()->set_cluster(kDefaultClusterName);
- // Construct CDS resource.
- default_cluster_.set_name(kDefaultClusterName);
- default_cluster_.set_type(Cluster::EDS);
- auto* eds_config = default_cluster_.mutable_eds_cluster_config();
- eds_config->mutable_eds_config()->mutable_self();
- eds_config->set_service_name(kDefaultEdsServiceName);
- default_cluster_.set_lb_policy(Cluster::ROUND_ROBIN);
- if (GetParam().enable_load_reporting()) {
- default_cluster_.mutable_lrs_server()->mutable_self();
- }
- // Construct a default server-side RDS resource for tests to use.
- default_server_route_config_.set_name(kDefaultServerRouteConfigurationName);
- virtual_host = default_server_route_config_.add_virtual_hosts();
- virtual_host->add_domains("*");
- route = virtual_host->add_routes();
- route->mutable_match()->set_prefix("");
- route->mutable_non_forwarding_action();
- // Construct a default server-side Listener resource
- default_server_listener_.mutable_address()
- ->mutable_socket_address()
- ->set_address(ipv6_only_ ? "::1" : "127.0.0.1");
- default_server_listener_.mutable_default_filter_chain()
- ->add_filters()
- ->mutable_typed_config()
- ->PackFrom(http_connection_manager);
- }
- void CreateClientsAndServers(BootstrapBuilder builder = BootstrapBuilder(),
- std::string lb_expected_authority = "") {
- // Create the backends but don't start them yet. We need to create the
- // backends to allocate the ports, so that the xDS servers know what
- // default resources to populate when we create them. However, we can't
- // start the backends until after we've started the xDS servers, because
- // in the tests that use xDS-enabled servers, the backends will try to
- // contact the xDS servers as soon as they start up.
- for (size_t i = 0; i < num_backends_; ++i) {
- backends_.emplace_back(new BackendServerThread(this));
- }
- // Start the load balancer.
- balancer_ = CreateAndStartBalancer();
- // Initialize resources on balancer.
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- default_route_config_);
- if (use_xds_enabled_server_) {
- for (const auto& backend : backends_) {
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backend->port(),
- default_server_route_config_);
- }
- }
- balancer_->ads_service()->SetCdsResource(default_cluster_);
- // Create fake resolver response generators used by client.
- logical_dns_cluster_resolver_response_generator_ =
- grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
- if (xds_resource_does_not_exist_timeout_ms_ > 0) {
- xds_channel_args_to_add_.emplace_back(grpc_channel_arg_integer_create(
- const_cast<char*>(GRPC_ARG_XDS_RESOURCE_DOES_NOT_EXIST_TIMEOUT_MS),
- xds_resource_does_not_exist_timeout_ms_));
- }
- if (!lb_expected_authority.empty()) {
- constexpr char authority_const[] = "localhost:%d";
- if (lb_expected_authority == authority_const) {
- lb_expected_authority =
- absl::StrFormat(authority_const, balancer_->port());
- }
- xds_channel_args_to_add_.emplace_back(grpc_channel_arg_string_create(
- const_cast<char*>(GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS),
- const_cast<char*>(lb_expected_authority.c_str())));
- }
- xds_channel_args_.num_args = xds_channel_args_to_add_.size();
- xds_channel_args_.args = xds_channel_args_to_add_.data();
- // Initialize XdsClient state.
- builder.SetDefaultServer(absl::StrCat("localhost:", balancer_->port()));
- if (GetParam().use_v2()) {
- builder.SetV2();
- }
- bootstrap_ = builder.Build();
- if (GetParam().bootstrap_source() == TestType::kBootstrapFromEnvVar) {
- gpr_setenv("GRPC_XDS_BOOTSTRAP_CONFIG", bootstrap_.c_str());
- } else if (GetParam().bootstrap_source() == TestType::kBootstrapFromFile) {
- FILE* out = gpr_tmpfile("xds_bootstrap_v3", &bootstrap_file_);
- fputs(bootstrap_.c_str(), out);
- fclose(out);
- gpr_setenv("GRPC_XDS_BOOTSTRAP", bootstrap_file_);
- }
- if (GetParam().bootstrap_source() != TestType::kBootstrapFromChannelArg) {
- // If getting bootstrap from channel arg, we'll pass these args in
- // via the parent channel args in CreateChannel() instead.
- grpc_core::internal::SetXdsChannelArgsForTest(&xds_channel_args_);
- // Make sure each test creates a new XdsClient instance rather than
- // reusing the one from the previous test. This avoids spurious failures
- // caused when a load reporting test runs after a non-load reporting test
- // and the XdsClient is still talking to the old LRS server, which fails
- // because it's not expecting the client to connect. It also
- // ensures that each test can independently set the global channel
- // args for the xDS channel.
- grpc_core::internal::UnsetGlobalXdsClientForTest();
- }
- // Create channel and stub.
- ResetStub();
- }
- void SetUp() override { CreateClientsAndServers(); }
- void TearDown() override {
- ShutdownAllBackends();
- balancer_->Shutdown();
- // Clear global xDS channel args, since they will go out of scope
- // when this test object is destroyed.
- grpc_core::internal::SetXdsChannelArgsForTest(nullptr);
- gpr_unsetenv("GRPC_XDS_BOOTSTRAP");
- gpr_unsetenv("GRPC_XDS_BOOTSTRAP_CONFIG");
- if (bootstrap_file_ != nullptr) {
- remove(bootstrap_file_);
- gpr_free(bootstrap_file_);
- }
- }
- void StartAllBackends() {
- for (auto& backend : backends_) backend->Start();
- }
- void StartBackend(size_t index) { backends_[index]->Start(); }
- void ShutdownAllBackends() {
- for (auto& backend : backends_) backend->Shutdown();
- }
- void ShutdownBackend(size_t index) { backends_[index]->Shutdown(); }
- std::unique_ptr<BalancerServerThread> CreateAndStartBalancer() {
- std::unique_ptr<BalancerServerThread> balancer =
- absl::make_unique<BalancerServerThread>(this);
- balancer->Start();
- return balancer;
- }
- void ResetStub(int failover_timeout = 0) {
- channel_ = CreateChannel(failover_timeout);
- stub_ = grpc::testing::EchoTestService::NewStub(channel_);
- stub1_ = grpc::testing::EchoTest1Service::NewStub(channel_);
- stub2_ = grpc::testing::EchoTest2Service::NewStub(channel_);
- }
- std::shared_ptr<Channel> CreateChannel(
- int failover_timeout = 0, const char* server_name = kServerName,
- const char* xds_authority = "",
- grpc_channel_args* xds_channel_args = nullptr) {
- ChannelArguments args;
- // TODO(roth): Remove this once we enable retries by default internally.
- args.SetInt(GRPC_ARG_ENABLE_RETRIES, 1);
- if (failover_timeout > 0) {
- args.SetInt(GRPC_ARG_PRIORITY_FAILOVER_TIMEOUT_MS, failover_timeout);
- }
- if (GetParam().bootstrap_source() == TestType::kBootstrapFromChannelArg) {
- // We're getting the bootstrap from a channel arg, so we do the
- // same thing for the response generator to use for the xDS
- // channel and the xDS resource-does-not-exist timeout value.
- args.SetString(GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG,
- bootstrap_.c_str());
- if (xds_channel_args == nullptr) xds_channel_args = &xds_channel_args_;
- args.SetPointerWithVtable(
- GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS,
- xds_channel_args, &kChannelArgsArgVtable);
- }
- args.SetPointerWithVtable(
- GRPC_ARG_XDS_LOGICAL_DNS_CLUSTER_FAKE_RESOLVER_RESPONSE_GENERATOR,
- logical_dns_cluster_resolver_response_generator_.get(),
- &grpc_core::FakeResolverResponseGenerator::kChannelArgPointerVtable);
- std::string uri = absl::StrCat("xds://", xds_authority, "/", server_name);
- std::shared_ptr<ChannelCredentials> channel_creds =
- GetParam().use_xds_credentials()
- ? XdsCredentials(CreateTlsFallbackCredentials())
- : std::make_shared<SecureChannelCredentials>(
- grpc_fake_transport_security_credentials_create());
- return grpc::CreateCustomChannel(uri, channel_creds, args);
- }
- enum RpcService {
- SERVICE_ECHO,
- SERVICE_ECHO1,
- SERVICE_ECHO2,
- };
- enum RpcMethod {
- METHOD_ECHO,
- METHOD_ECHO1,
- METHOD_ECHO2,
- };
- struct RpcOptions {
- RpcService service = SERVICE_ECHO;
- RpcMethod method = METHOD_ECHO;
- int timeout_ms = 1000;
- bool wait_for_ready = false;
- bool server_fail = false;
- std::vector<std::pair<std::string, std::string>> metadata;
- int server_sleep_us = 0;
- int client_cancel_after_us = 0;
- bool skip_cancelled_check = false;
- StatusCode server_expected_error = StatusCode::OK;
- RpcOptions() {}
- RpcOptions& set_rpc_service(RpcService rpc_service) {
- service = rpc_service;
- return *this;
- }
- RpcOptions& set_rpc_method(RpcMethod rpc_method) {
- method = rpc_method;
- return *this;
- }
- RpcOptions& set_timeout_ms(int rpc_timeout_ms) {
- timeout_ms = rpc_timeout_ms;
- return *this;
- }
- RpcOptions& set_wait_for_ready(bool rpc_wait_for_ready) {
- wait_for_ready = rpc_wait_for_ready;
- return *this;
- }
- RpcOptions& set_server_fail(bool rpc_server_fail) {
- server_fail = rpc_server_fail;
- return *this;
- }
- RpcOptions& set_skip_cancelled_check(bool rpc_skip_cancelled_check) {
- skip_cancelled_check = rpc_skip_cancelled_check;
- return *this;
- }
- RpcOptions& set_metadata(
- std::vector<std::pair<std::string, std::string>> rpc_metadata) {
- metadata = std::move(rpc_metadata);
- return *this;
- }
- RpcOptions& set_server_sleep_us(int rpc_server_sleep_us) {
- server_sleep_us = rpc_server_sleep_us;
- return *this;
- }
- RpcOptions& set_client_cancel_after_us(int rpc_client_cancel_after_us) {
- client_cancel_after_us = rpc_client_cancel_after_us;
- return *this;
- }
- RpcOptions& set_server_expected_error(StatusCode code) {
- server_expected_error = code;
- return *this;
- }
- // Populates context and request.
- void SetupRpc(ClientContext* context, EchoRequest* request) const {
- for (const auto& item : metadata) {
- context->AddMetadata(item.first, item.second);
- }
- if (timeout_ms != 0) {
- context->set_deadline(
- grpc_timeout_milliseconds_to_deadline(timeout_ms));
- }
- if (wait_for_ready) context->set_wait_for_ready(true);
- request->set_message(kRequestMessage);
- if (server_fail) {
- request->mutable_param()->mutable_expected_error()->set_code(
- GRPC_STATUS_FAILED_PRECONDITION);
- }
- if (server_sleep_us != 0) {
- request->mutable_param()->set_server_sleep_us(server_sleep_us);
- }
- if (client_cancel_after_us != 0) {
- request->mutable_param()->set_client_cancel_after_us(
- client_cancel_after_us);
- }
- if (skip_cancelled_check) {
- request->mutable_param()->set_skip_cancelled_check(true);
- }
- }
- };
- template <typename Stub>
- Status SendRpcMethod(Stub* stub, const RpcOptions& rpc_options,
- ClientContext* context, EchoRequest& request,
- EchoResponse* response) {
- switch (rpc_options.method) {
- case METHOD_ECHO:
- return stub->Echo(context, request, response);
- case METHOD_ECHO1:
- return stub->Echo1(context, request, response);
- case METHOD_ECHO2:
- return stub->Echo2(context, request, response);
- }
- GPR_UNREACHABLE_CODE();
- }
- void ResetBackendCounters(size_t start_index = 0, size_t stop_index = 0) {
- if (stop_index == 0) stop_index = backends_.size();
- for (size_t i = start_index; i < stop_index; ++i) {
- backends_[i]->backend_service()->ResetCounters();
- backends_[i]->backend_service1()->ResetCounters();
- backends_[i]->backend_service2()->ResetCounters();
- }
- }
- bool SeenBackend(size_t backend_idx,
- const RpcService rpc_service = SERVICE_ECHO) {
- switch (rpc_service) {
- case SERVICE_ECHO:
- if (backends_[backend_idx]->backend_service()->request_count() == 0) {
- return false;
- }
- break;
- case SERVICE_ECHO1:
- if (backends_[backend_idx]->backend_service1()->request_count() == 0) {
- return false;
- }
- break;
- case SERVICE_ECHO2:
- if (backends_[backend_idx]->backend_service2()->request_count() == 0) {
- return false;
- }
- break;
- }
- return true;
- }
- bool SeenAllBackends(size_t start_index = 0, size_t stop_index = 0,
- const RpcService rpc_service = SERVICE_ECHO) {
- if (stop_index == 0) stop_index = backends_.size();
- for (size_t i = start_index; i < stop_index; ++i) {
- if (!SeenBackend(i, rpc_service)) {
- return false;
- }
- }
- return true;
- }
- // Sends num_rpcs RPCs, counting how many of them fail with a message
- // matching the specfied drop_error_message_prefix.
- // Any failure with a non-matching message is a test failure.
- size_t SendRpcsAndCountFailuresWithMessage(
- size_t num_rpcs, const char* drop_error_message_prefix,
- const RpcOptions& rpc_options = RpcOptions()) {
- size_t num_failed = 0;
- for (size_t i = 0; i < num_rpcs; ++i) {
- Status status = SendRpc(rpc_options);
- if (!status.ok()) {
- EXPECT_THAT(status.error_message(),
- ::testing::StartsWith(drop_error_message_prefix))
- << "code=" << status.error_code()
- << " message=" << status.error_message();
- ++num_failed;
- }
- }
- return num_failed;
- }
- struct WaitForBackendOptions {
- bool reset_counters = true;
- bool allow_failures = false;
- int timeout_ms = 5000;
- WaitForBackendOptions() {}
- WaitForBackendOptions& set_reset_counters(bool enable) {
- reset_counters = enable;
- return *this;
- }
- WaitForBackendOptions& set_allow_failures(bool enable) {
- allow_failures = enable;
- return *this;
- }
- WaitForBackendOptions& set_timeout_ms(int ms) {
- timeout_ms = ms;
- return *this;
- }
- };
- // Returns the total number of RPCs sent.
- size_t WaitForAllBackends(
- size_t start_index = 0, size_t stop_index = 0,
- const WaitForBackendOptions& wait_options = WaitForBackendOptions(),
- const RpcOptions& rpc_options = RpcOptions()) {
- size_t num_rpcs = 0;
- auto deadline = absl::Now() + (absl::Milliseconds(wait_options.timeout_ms) *
- grpc_test_slowdown_factor());
- gpr_log(GPR_INFO,
- "========= WAITING FOR BACKENDS [%" PRIuPTR ", %" PRIuPTR
- ") ==========",
- start_index, stop_index);
- while (!SeenAllBackends(start_index, stop_index, rpc_options.service)) {
- Status status = SendRpc(rpc_options);
- if (!wait_options.allow_failures) {
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- EXPECT_LE(absl::Now(), deadline);
- if (absl::Now() >= deadline) break;
- ++num_rpcs;
- }
- if (wait_options.reset_counters) ResetBackendCounters();
- gpr_log(GPR_INFO, "Backends up; sent %" PRIuPTR " warm up requests",
- num_rpcs);
- return num_rpcs;
- }
- void WaitForBackend(
- size_t backend_idx,
- const WaitForBackendOptions& wait_options = WaitForBackendOptions(),
- const RpcOptions& rpc_options = RpcOptions()) {
- WaitForAllBackends(backend_idx, backend_idx + 1, wait_options, rpc_options);
- }
- grpc_core::ServerAddressList CreateAddressListFromPortList(
- const std::vector<int>& ports) {
- grpc_core::ServerAddressList addresses;
- for (int port : ports) {
- absl::StatusOr<grpc_core::URI> lb_uri = grpc_core::URI::Parse(
- absl::StrCat(ipv6_only_ ? "ipv6:[::1]:" : "ipv4:127.0.0.1:", port));
- GPR_ASSERT(lb_uri.ok());
- grpc_resolved_address address;
- GPR_ASSERT(grpc_parse_uri(*lb_uri, &address));
- addresses.emplace_back(address.addr, address.len, nullptr);
- }
- return addresses;
- }
- std::string CreateMetadataValueThatHashesToBackendPort(int port) {
- return absl::StrCat(ipv6_only_ ? "[::1]" : "127.0.0.1", ":", port, "_0");
- }
- std::string CreateMetadataValueThatHashesToBackend(int index) {
- return CreateMetadataValueThatHashesToBackendPort(backends_[index]->port());
- }
- std::vector<int> GetBackendPorts(size_t start_index = 0,
- size_t stop_index = 0) const {
- if (stop_index == 0) stop_index = backends_.size();
- std::vector<int> backend_ports;
- for (size_t i = start_index; i < stop_index; ++i) {
- backend_ports.push_back(backends_[i]->port());
- }
- return backend_ports;
- }
- Status SendRpc(const RpcOptions& rpc_options = RpcOptions(),
- EchoResponse* response = nullptr) {
- const bool local_response = (response == nullptr);
- if (local_response) response = new EchoResponse;
- ClientContext context;
- EchoRequest request;
- if (rpc_options.server_expected_error != StatusCode::OK) {
- auto* error = request.mutable_param()->mutable_expected_error();
- error->set_code(rpc_options.server_expected_error);
- }
- rpc_options.SetupRpc(&context, &request);
- Status status;
- switch (rpc_options.service) {
- case SERVICE_ECHO:
- status = SendRpcMethod(stub_.get(), rpc_options, &context, request,
- response);
- break;
- case SERVICE_ECHO1:
- status = SendRpcMethod(stub1_.get(), rpc_options, &context, request,
- response);
- break;
- case SERVICE_ECHO2:
- status = SendRpcMethod(stub2_.get(), rpc_options, &context, request,
- response);
- break;
- }
- if (local_response) delete response;
- return status;
- }
- void CheckRpcSendOk(const size_t times = 1,
- const RpcOptions& rpc_options = RpcOptions()) {
- for (size_t i = 0; i < times; ++i) {
- EchoResponse response;
- const Status status = SendRpc(rpc_options, &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- EXPECT_EQ(response.message(), kRequestMessage);
- }
- }
- struct CheckRpcSendFailureOptions {
- std::function<bool(size_t)> continue_predicate = [](size_t i) {
- return i < 1;
- };
- RpcOptions rpc_options;
- StatusCode expected_error_code = StatusCode::OK;
- CheckRpcSendFailureOptions() {}
- CheckRpcSendFailureOptions& set_times(size_t times) {
- continue_predicate = [times](size_t i) { return i < times; };
- return *this;
- }
- CheckRpcSendFailureOptions& set_continue_predicate(
- std::function<bool(size_t)> pred) {
- continue_predicate = std::move(pred);
- return *this;
- }
- CheckRpcSendFailureOptions& set_rpc_options(const RpcOptions& options) {
- rpc_options = options;
- return *this;
- }
- CheckRpcSendFailureOptions& set_expected_error_code(StatusCode code) {
- expected_error_code = code;
- return *this;
- }
- };
- void CheckRpcSendFailure(const CheckRpcSendFailureOptions& options =
- CheckRpcSendFailureOptions()) {
- for (size_t i = 0; options.continue_predicate(i); ++i) {
- const Status status = SendRpc(options.rpc_options);
- EXPECT_FALSE(status.ok());
- if (options.expected_error_code != StatusCode::OK) {
- EXPECT_EQ(options.expected_error_code, status.error_code())
- << "code=" << status.error_code()
- << " message=" << status.error_message();
- ;
- }
- }
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForNack(
- std::function<absl::optional<AdsServiceImpl::ResponseState>()> get_state,
- StatusCode expected_status = StatusCode::UNAVAILABLE) {
- absl::optional<AdsServiceImpl::ResponseState> response_state;
- auto deadline = absl::Now() + absl::Seconds(30);
- auto continue_predicate = [&]() {
- if (absl::Now() >= deadline) {
- return false;
- }
- response_state = get_state();
- return !response_state.has_value() ||
- response_state->state != AdsServiceImpl::ResponseState::NACKED;
- };
- do {
- const Status status = SendRpc();
- EXPECT_EQ(expected_status, status.error_code())
- << "code=" << status.error_code()
- << " message=" << status.error_message();
- ;
- } while (continue_predicate());
- return response_state;
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForLdsNack(
- StatusCode expected_status = StatusCode::UNAVAILABLE) {
- return WaitForNack(
- [&]() { return balancer_->ads_service()->lds_response_state(); },
- expected_status);
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForRdsNack(
- StatusCode expected_status = StatusCode::UNAVAILABLE) {
- return WaitForNack(
- [&]() { return RouteConfigurationResponseState(balancer_.get()); },
- expected_status);
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForCdsNack(
- StatusCode expected_status = StatusCode::UNAVAILABLE) {
- return WaitForNack(
- [&]() { return balancer_->ads_service()->cds_response_state(); },
- expected_status);
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForEdsNack() {
- return WaitForNack(
- [&]() { return balancer_->ads_service()->eds_response_state(); });
- }
- absl::optional<AdsServiceImpl::ResponseState> WaitForRouteConfigNack(
- StatusCode expected_status = StatusCode::UNAVAILABLE) {
- if (GetParam().enable_rds_testing()) {
- return WaitForRdsNack(expected_status);
- }
- return WaitForLdsNack(expected_status);
- }
- absl::optional<AdsServiceImpl::ResponseState> RouteConfigurationResponseState(
- BalancerServerThread* balancer) const {
- AdsServiceImpl* ads_service = balancer->ads_service();
- if (GetParam().enable_rds_testing()) {
- return ads_service->rds_response_state();
- }
- return ads_service->lds_response_state();
- }
- std::string GetServerListenerName(int port) {
- return absl::StrCat("grpc/server?xds.resource.listening_address=",
- ipv6_only_ ? "[::1]:" : "127.0.0.1:", port);
- }
- Listener PopulateServerListenerNameAndPort(const Listener& listener_template,
- int port) {
- Listener listener = listener_template;
- listener.set_name(GetServerListenerName(port));
- listener.mutable_address()->mutable_socket_address()->set_port_value(port);
- return listener;
- }
- // Interface for accessing HttpConnectionManager config in Listener.
- class HcmAccessor {
- public:
- virtual ~HcmAccessor() = default;
- virtual HttpConnectionManager Unpack(const Listener& listener) const = 0;
- virtual void Pack(const HttpConnectionManager& hcm,
- Listener* listener) const = 0;
- };
- // Client-side impl.
- class ClientHcmAccessor : public HcmAccessor {
- public:
- HttpConnectionManager Unpack(const Listener& listener) const override {
- HttpConnectionManager http_connection_manager;
- listener.api_listener().api_listener().UnpackTo(&http_connection_manager);
- return http_connection_manager;
- }
- void Pack(const HttpConnectionManager& hcm,
- Listener* listener) const override {
- auto* api_listener =
- listener->mutable_api_listener()->mutable_api_listener();
- api_listener->PackFrom(hcm);
- }
- };
- // Server-side impl.
- class ServerHcmAccessor : public HcmAccessor {
- public:
- HttpConnectionManager Unpack(const Listener& listener) const override {
- HttpConnectionManager http_connection_manager;
- listener.default_filter_chain().filters().at(0).typed_config().UnpackTo(
- &http_connection_manager);
- return http_connection_manager;
- }
- void Pack(const HttpConnectionManager& hcm,
- Listener* listener) const override {
- listener->mutable_default_filter_chain()
- ->mutable_filters()
- ->at(0)
- .mutable_typed_config()
- ->PackFrom(hcm);
- }
- };
- void SetListenerAndRouteConfiguration(
- BalancerServerThread* balancer, Listener listener,
- const RouteConfiguration& route_config,
- const HcmAccessor& hcm_accessor = ClientHcmAccessor()) {
- HttpConnectionManager http_connection_manager =
- hcm_accessor.Unpack(listener);
- if (GetParam().enable_rds_testing()) {
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(route_config.name());
- rds->mutable_config_source()->mutable_self();
- balancer->ads_service()->SetRdsResource(route_config);
- } else {
- *http_connection_manager.mutable_route_config() = route_config;
- }
- hcm_accessor.Pack(http_connection_manager, &listener);
- balancer->ads_service()->SetLdsResource(listener);
- }
- void SetServerListenerNameAndRouteConfiguration(
- BalancerServerThread* balancer, Listener listener, int port,
- const RouteConfiguration& route_config) {
- SetListenerAndRouteConfiguration(
- balancer, PopulateServerListenerNameAndPort(listener, port),
- route_config, ServerHcmAccessor());
- }
- void SetRouteConfiguration(BalancerServerThread* balancer,
- const RouteConfiguration& route_config,
- const Listener* listener_to_copy = nullptr) {
- if (GetParam().enable_rds_testing()) {
- balancer->ads_service()->SetRdsResource(route_config);
- } else {
- Listener listener(listener_to_copy == nullptr ? default_listener_
- : *listener_to_copy);
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *(http_connection_manager.mutable_route_config()) = route_config;
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- balancer->ads_service()->SetLdsResource(listener);
- }
- }
- struct EdsResourceArgs {
- struct Endpoint {
- explicit Endpoint(int port,
- HealthStatus health_status = HealthStatus::UNKNOWN,
- int lb_weight = 1)
- : port(port), health_status(health_status), lb_weight(lb_weight) {}
- int port;
- HealthStatus health_status;
- int lb_weight;
- };
- struct Locality {
- Locality(std::string sub_zone, std::vector<Endpoint> endpoints,
- int lb_weight = kDefaultLocalityWeight,
- int priority = kDefaultLocalityPriority)
- : sub_zone(std::move(sub_zone)),
- endpoints(std::move(endpoints)),
- lb_weight(lb_weight),
- priority(priority) {}
- const std::string sub_zone;
- std::vector<Endpoint> endpoints;
- int lb_weight;
- int priority;
- };
- EdsResourceArgs() = default;
- explicit EdsResourceArgs(std::vector<Locality> locality_list)
- : locality_list(std::move(locality_list)) {}
- std::vector<Locality> locality_list;
- std::map<std::string, uint32_t> drop_categories;
- FractionalPercent::DenominatorType drop_denominator =
- FractionalPercent::MILLION;
- };
- EdsResourceArgs::Endpoint CreateEndpoint(
- size_t backend_idx, HealthStatus health_status = HealthStatus::UNKNOWN,
- int lb_weight = 1) {
- return EdsResourceArgs::Endpoint(backends_[backend_idx]->port(),
- health_status, lb_weight);
- }
- std::vector<EdsResourceArgs::Endpoint> CreateEndpointsForBackends(
- size_t start_index = 0, size_t stop_index = 0,
- HealthStatus health_status = HealthStatus::UNKNOWN, int lb_weight = 1) {
- if (stop_index == 0) stop_index = backends_.size();
- std::vector<EdsResourceArgs::Endpoint> endpoints;
- for (size_t i = start_index; i < stop_index; ++i) {
- endpoints.emplace_back(CreateEndpoint(i, health_status, lb_weight));
- }
- return endpoints;
- }
- EdsResourceArgs::Endpoint MakeNonExistantEndpoint() {
- return EdsResourceArgs::Endpoint(grpc_pick_unused_port_or_die());
- }
- ClusterLoadAssignment BuildEdsResource(
- const EdsResourceArgs& args,
- const char* eds_service_name = kDefaultEdsServiceName) {
- ClusterLoadAssignment assignment;
- assignment.set_cluster_name(eds_service_name);
- for (const auto& locality : args.locality_list) {
- auto* endpoints = assignment.add_endpoints();
- endpoints->mutable_load_balancing_weight()->set_value(locality.lb_weight);
- endpoints->set_priority(locality.priority);
- endpoints->mutable_locality()->set_region(kDefaultLocalityRegion);
- endpoints->mutable_locality()->set_zone(kDefaultLocalityZone);
- endpoints->mutable_locality()->set_sub_zone(locality.sub_zone);
- for (size_t i = 0; i < locality.endpoints.size(); ++i) {
- const int& port = locality.endpoints[i].port;
- auto* lb_endpoints = endpoints->add_lb_endpoints();
- if (locality.endpoints.size() > i &&
- locality.endpoints[i].health_status != HealthStatus::UNKNOWN) {
- lb_endpoints->set_health_status(locality.endpoints[i].health_status);
- }
- if (locality.endpoints.size() > i &&
- locality.endpoints[i].lb_weight >= 1) {
- lb_endpoints->mutable_load_balancing_weight()->set_value(
- locality.endpoints[i].lb_weight);
- }
- auto* endpoint = lb_endpoints->mutable_endpoint();
- auto* address = endpoint->mutable_address();
- auto* socket_address = address->mutable_socket_address();
- socket_address->set_address(ipv6_only_ ? "::1" : "127.0.0.1");
- socket_address->set_port_value(port);
- }
- }
- if (!args.drop_categories.empty()) {
- auto* policy = assignment.mutable_policy();
- for (const auto& p : args.drop_categories) {
- const std::string& name = p.first;
- const uint32_t parts_per_million = p.second;
- auto* drop_overload = policy->add_drop_overloads();
- drop_overload->set_category(name);
- auto* drop_percentage = drop_overload->mutable_drop_percentage();
- drop_percentage->set_numerator(parts_per_million);
- drop_percentage->set_denominator(args.drop_denominator);
- }
- }
- return assignment;
- }
- public:
- // This method could benefit test subclasses; to make it accessible
- // via bind with a qualified name, it needs to be public.
- void SetEdsResourceWithDelay(BalancerServerThread* balancer,
- const ClusterLoadAssignment& assignment,
- int delay_ms) {
- GPR_ASSERT(delay_ms > 0);
- gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(delay_ms));
- balancer->ads_service()->SetEdsResource(assignment);
- }
- protected:
- class XdsServingStatusNotifier
- : public grpc::experimental::XdsServerServingStatusNotifierInterface {
- public:
- void OnServingStatusUpdate(std::string uri,
- ServingStatusUpdate update) override {
- grpc_core::MutexLock lock(&mu_);
- status_map[uri] = update.status;
- cond_.Signal();
- }
- void WaitOnServingStatusChange(std::string uri,
- grpc::StatusCode expected_status) {
- grpc_core::MutexLock lock(&mu_);
- std::map<std::string, grpc::Status>::iterator it;
- while ((it = status_map.find(uri)) == status_map.end() ||
- it->second.error_code() != expected_status) {
- cond_.Wait(&mu_);
- }
- }
- private:
- grpc_core::Mutex mu_;
- grpc_core::CondVar cond_;
- std::map<std::string, grpc::Status> status_map ABSL_GUARDED_BY(mu_);
- };
- class ServerThread {
- public:
- explicit ServerThread(XdsEnd2endTest* test_obj,
- bool use_xds_enabled_server = false)
- : test_obj_(test_obj),
- port_(grpc_pick_unused_port_or_die()),
- use_xds_enabled_server_(use_xds_enabled_server) {}
- virtual ~ServerThread() { Shutdown(); }
- void Start() {
- gpr_log(GPR_INFO, "starting %s server on port %d", Type(), port_);
- GPR_ASSERT(!running_);
- running_ = true;
- StartAllServices();
- grpc_core::Mutex mu;
- // We need to acquire the lock here in order to prevent the notify_one
- // by ServerThread::Serve from firing before the wait below is hit.
- grpc_core::MutexLock lock(&mu);
- grpc_core::CondVar cond;
- thread_ = absl::make_unique<std::thread>(
- std::bind(&ServerThread::Serve, this, &mu, &cond));
- cond.Wait(&mu);
- gpr_log(GPR_INFO, "%s server startup complete", Type());
- }
- void Serve(grpc_core::Mutex* mu, grpc_core::CondVar* cond) {
- // We need to acquire the lock here in order to prevent the notify_one
- // below from firing before its corresponding wait is executed.
- grpc_core::MutexLock lock(mu);
- std::ostringstream server_address;
- server_address << "localhost:" << port_;
- if (use_xds_enabled_server_) {
- XdsServerBuilder builder;
- if (GetParam().bootstrap_source() ==
- TestType::kBootstrapFromChannelArg) {
- builder.SetOption(
- absl::make_unique<XdsChannelArgsServerBuilderOption>(test_obj_));
- }
- builder.set_status_notifier(¬ifier_);
- builder.experimental().set_drain_grace_time(
- test_obj_->xds_drain_grace_time_ms_);
- builder.AddListeningPort(server_address.str(), Credentials());
- RegisterAllServices(&builder);
- server_ = builder.BuildAndStart();
- } else {
- ServerBuilder builder;
- builder.AddListeningPort(server_address.str(), Credentials());
- RegisterAllServices(&builder);
- server_ = builder.BuildAndStart();
- }
- cond->Signal();
- }
- void Shutdown() {
- if (!running_) return;
- gpr_log(GPR_INFO, "%s about to shutdown", Type());
- ShutdownAllServices();
- server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0));
- thread_->join();
- gpr_log(GPR_INFO, "%s shutdown completed", Type());
- running_ = false;
- }
- virtual std::shared_ptr<ServerCredentials> Credentials() {
- return std::make_shared<SecureServerCredentials>(
- grpc_fake_transport_security_server_credentials_create());
- }
- int port() const { return port_; }
- bool use_xds_enabled_server() const { return use_xds_enabled_server_; }
- XdsServingStatusNotifier* notifier() { return ¬ifier_; }
- private:
- class XdsChannelArgsServerBuilderOption : public grpc::ServerBuilderOption {
- public:
- explicit XdsChannelArgsServerBuilderOption(XdsEnd2endTest* test_obj)
- : test_obj_(test_obj) {}
- void UpdateArguments(grpc::ChannelArguments* args) override {
- args->SetString(
- GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_BOOTSTRAP_CONFIG,
- test_obj_->bootstrap_);
- args->SetPointerWithVtable(
- GRPC_ARG_TEST_ONLY_DO_NOT_USE_IN_PROD_XDS_CLIENT_CHANNEL_ARGS,
- &test_obj_->xds_channel_args_, &kChannelArgsArgVtable);
- }
- void UpdatePlugins(
- std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>>* /*plugins*/)
- override {}
- private:
- XdsEnd2endTest* test_obj_;
- };
- virtual void RegisterAllServices(ServerBuilder* builder) = 0;
- virtual void StartAllServices() = 0;
- virtual void ShutdownAllServices() = 0;
- virtual const char* Type() = 0;
- XdsEnd2endTest* test_obj_;
- const int port_;
- std::unique_ptr<Server> server_;
- XdsServingStatusNotifier notifier_;
- std::unique_ptr<std::thread> thread_;
- bool running_ = false;
- const bool use_xds_enabled_server_;
- };
- class BackendServerThread : public ServerThread {
- public:
- explicit BackendServerThread(XdsEnd2endTest* test_obj)
- : ServerThread(test_obj, test_obj->use_xds_enabled_server_) {}
- BackendServiceImpl<grpc::testing::EchoTestService::Service>*
- backend_service() {
- return &backend_service_;
- }
- BackendServiceImpl<grpc::testing::EchoTest1Service::Service>*
- backend_service1() {
- return &backend_service1_;
- }
- BackendServiceImpl<grpc::testing::EchoTest2Service::Service>*
- backend_service2() {
- return &backend_service2_;
- }
- std::shared_ptr<ServerCredentials> Credentials() override {
- if (GetParam().use_xds_credentials()) {
- if (use_xds_enabled_server()) {
- // We are testing server's use of XdsServerCredentials
- return XdsServerCredentials(InsecureServerCredentials());
- } else {
- // We are testing client's use of XdsCredentials
- std::string root_cert = ReadFile(kCaCertPath);
- std::string identity_cert = ReadFile(kServerCertPath);
- std::string private_key = ReadFile(kServerKeyPath);
- std::vector<experimental::IdentityKeyCertPair>
- identity_key_cert_pairs = {{private_key, identity_cert}};
- auto certificate_provider = std::make_shared<
- grpc::experimental::StaticDataCertificateProvider>(
- root_cert, identity_key_cert_pairs);
- grpc::experimental::TlsServerCredentialsOptions options(
- certificate_provider);
- options.watch_root_certs();
- options.watch_identity_key_cert_pairs();
- options.set_cert_request_type(
- GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
- return grpc::experimental::TlsServerCredentials(options);
- }
- }
- return ServerThread::Credentials();
- }
- private:
- void RegisterAllServices(ServerBuilder* builder) override {
- builder->RegisterService(&backend_service_);
- builder->RegisterService(&backend_service1_);
- builder->RegisterService(&backend_service2_);
- }
- void StartAllServices() override {
- backend_service_.Start();
- backend_service1_.Start();
- backend_service2_.Start();
- }
- void ShutdownAllServices() override {
- backend_service_.Shutdown();
- backend_service1_.Shutdown();
- backend_service2_.Shutdown();
- }
- const char* Type() override { return "Backend"; }
- BackendServiceImpl<grpc::testing::EchoTestService::Service>
- backend_service_;
- BackendServiceImpl<grpc::testing::EchoTest1Service::Service>
- backend_service1_;
- BackendServiceImpl<grpc::testing::EchoTest2Service::Service>
- backend_service2_;
- };
- class BalancerServerThread : public ServerThread {
- public:
- explicit BalancerServerThread(XdsEnd2endTest* test_obj)
- : ServerThread(test_obj, /*use_xds_enabled_server=*/false),
- ads_service_(new AdsServiceImpl()),
- lrs_service_(new LrsServiceImpl(
- (GetParam().enable_load_reporting()
- ? test_obj->client_load_reporting_interval_seconds_
- : 0),
- {kDefaultClusterName})) {}
- AdsServiceImpl* ads_service() { return ads_service_.get(); }
- LrsServiceImpl* lrs_service() { return lrs_service_.get(); }
- private:
- void RegisterAllServices(ServerBuilder* builder) override {
- builder->RegisterService(ads_service_->v2_rpc_service());
- builder->RegisterService(ads_service_->v3_rpc_service());
- builder->RegisterService(lrs_service_->v2_rpc_service());
- builder->RegisterService(lrs_service_->v3_rpc_service());
- }
- void StartAllServices() override {
- ads_service_->Start();
- lrs_service_->Start();
- }
- void ShutdownAllServices() override {
- ads_service_->Shutdown();
- lrs_service_->Shutdown();
- }
- const char* Type() override { return "Balancer"; }
- std::shared_ptr<AdsServiceImpl> ads_service_;
- std::shared_ptr<LrsServiceImpl> lrs_service_;
- };
- #ifndef DISABLED_XDS_PROTO_IN_CC
- class AdminServerThread : public ServerThread {
- public:
- explicit AdminServerThread(XdsEnd2endTest* test_obj)
- : ServerThread(test_obj) {}
- private:
- void RegisterAllServices(ServerBuilder* builder) override {
- builder->RegisterService(&csds_service_);
- }
- void StartAllServices() override {}
- void ShutdownAllServices() override {}
- const char* Type() override { return "Admin"; }
- grpc::xds::experimental::ClientStatusDiscoveryService csds_service_;
- };
- #endif // DISABLED_XDS_PROTO_IN_CC
- class LongRunningRpc {
- public:
- void StartRpc(grpc::testing::EchoTestService::Stub* stub,
- const RpcOptions& rpc_options =
- RpcOptions().set_timeout_ms(0).set_client_cancel_after_us(
- 1 * 1000 * 1000)) {
- sender_thread_ = std::thread([this, stub, rpc_options]() {
- EchoRequest request;
- EchoResponse response;
- rpc_options.SetupRpc(&context_, &request);
- status_ = stub->Echo(&context_, request, &response);
- });
- }
- void CancelRpc() {
- context_.TryCancel();
- if (sender_thread_.joinable()) sender_thread_.join();
- }
- Status GetStatus() {
- if (sender_thread_.joinable()) sender_thread_.join();
- return status_;
- }
- private:
- std::thread sender_thread_;
- ClientContext context_;
- Status status_;
- };
- struct ConcurrentRpc {
- ClientContext context;
- Status status;
- grpc_core::Duration elapsed_time;
- EchoResponse response;
- };
- std::vector<ConcurrentRpc> SendConcurrentRpcs(
- grpc::testing::EchoTestService::Stub* stub, size_t num_rpcs,
- const RpcOptions& rpc_options) {
- // Variables for RPCs.
- std::vector<ConcurrentRpc> rpcs(num_rpcs);
- EchoRequest request;
- // Variables for synchronization
- absl::Mutex mu;
- absl::CondVar cv;
- size_t completed = 0;
- // Set-off callback RPCs
- for (size_t i = 0; i < num_rpcs; i++) {
- ConcurrentRpc* rpc = &rpcs[i];
- rpc_options.SetupRpc(&rpc->context, &request);
- grpc_core::Timestamp t0 = NowFromCycleCounter();
- stub->async()->Echo(&rpc->context, &request, &rpc->response,
- [rpc, &mu, &completed, &cv, num_rpcs, t0](Status s) {
- rpc->status = s;
- rpc->elapsed_time = NowFromCycleCounter() - t0;
- bool done;
- {
- absl::MutexLock lock(&mu);
- done = (++completed) == num_rpcs;
- }
- if (done) cv.Signal();
- });
- }
- {
- absl::MutexLock lock(&mu);
- cv.Wait(&mu);
- }
- EXPECT_EQ(completed, num_rpcs);
- return rpcs;
- }
- const size_t num_backends_;
- const int client_load_reporting_interval_seconds_;
- bool ipv6_only_ = false;
- std::shared_ptr<Channel> channel_;
- std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
- std::unique_ptr<grpc::testing::EchoTest1Service::Stub> stub1_;
- std::unique_ptr<grpc::testing::EchoTest2Service::Stub> stub2_;
- std::vector<std::unique_ptr<BackendServerThread>> backends_;
- std::unique_ptr<BalancerServerThread> balancer_;
- grpc_core::RefCountedPtr<grpc_core::FakeResolverResponseGenerator>
- logical_dns_cluster_resolver_response_generator_;
- int xds_resource_does_not_exist_timeout_ms_ = 0;
- absl::InlinedVector<grpc_arg, 3> xds_channel_args_to_add_;
- grpc_channel_args xds_channel_args_;
- Listener default_listener_;
- RouteConfiguration default_route_config_;
- Listener default_server_listener_;
- RouteConfiguration default_server_route_config_;
- Cluster default_cluster_;
- bool use_xds_enabled_server_;
- int xds_drain_grace_time_ms_ = 10 * 60 * 1000; // 10 mins
- bool bootstrap_contents_from_env_var_;
- std::string bootstrap_;
- char* bootstrap_file_ = nullptr;
- };
- class BasicTest : public XdsEnd2endTest {
- public:
- BasicTest() : XdsEnd2endTest(4) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- };
- // Tests that the balancer sends the correct response to the client, and the
- // client sends RPCs to the backends using the default child policy.
- TEST_P(BasicTest, Vanilla) {
- const size_t kNumRpcsPerAddress = 100;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Make sure that trying to connect works without a call.
- channel_->GetState(true /* try_to_connect */);
- // We need to wait for all backends to come online.
- WaitForAllBackends();
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * num_backends_);
- // Each backend should have gotten 100 requests.
- for (size_t i = 0; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- // Check LB policy name for the channel.
- EXPECT_EQ("xds_cluster_manager_experimental",
- channel_->GetLoadBalancingPolicyName());
- }
- TEST_P(BasicTest, IgnoresUnhealthyEndpoints) {
- const size_t kNumRpcsPerAddress = 100;
- auto endpoints = CreateEndpointsForBackends();
- endpoints[0].health_status = HealthStatus::DRAINING;
- EdsResourceArgs args({
- {"locality0", std::move(endpoints), kDefaultLocalityWeight,
- kDefaultLocalityPriority},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Make sure that trying to connect works without a call.
- channel_->GetState(true /* try_to_connect */);
- // We need to wait for all backends to come online.
- WaitForAllBackends(/*start_index=*/1);
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * (num_backends_ - 1));
- // Each backend should have gotten 100 requests.
- for (size_t i = 1; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- }
- // Tests that subchannel sharing works when the same backend is listed
- // multiple times.
- TEST_P(BasicTest, SameBackendListedMultipleTimes) {
- // Same backend listed twice.
- auto endpoints = CreateEndpointsForBackends(0, 1);
- endpoints.push_back(endpoints.front());
- EdsResourceArgs args({
- {"locality0", endpoints},
- });
- const size_t kNumRpcsPerAddress = 10;
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for the backend to come online.
- WaitForBackend(0);
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * endpoints.size());
- // Backend should have gotten 20 requests.
- EXPECT_EQ(kNumRpcsPerAddress * endpoints.size(),
- backends_[0]->backend_service()->request_count());
- // And they should have come from a single client port, because of
- // subchannel sharing.
- EXPECT_EQ(1UL, backends_[0]->backend_service()->clients().size());
- }
- // Tests that RPCs will be blocked until a non-empty serverlist is received.
- TEST_P(BasicTest, InitiallyEmptyServerlist) {
- const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor();
- const int kCallDeadlineMs = kServerlistDelayMs * 2;
- // First response is an empty serverlist, sent right away.
- EdsResourceArgs::Locality empty_locality("locality0", {});
- EdsResourceArgs args({
- empty_locality,
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send non-empty serverlist only after kServerlistDelayMs.
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends()},
- });
- std::thread delayed_resource_setter(
- std::bind(&BasicTest::SetEdsResourceWithDelay, this, balancer_.get(),
- BuildEdsResource(args), kServerlistDelayMs));
- const auto t0 = system_clock::now();
- // Client will block: LB will initially send empty serverlist.
- CheckRpcSendOk(
- 1, RpcOptions().set_timeout_ms(kCallDeadlineMs).set_wait_for_ready(true));
- const auto ellapsed_ms =
- std::chrono::duration_cast<std::chrono::milliseconds>(
- system_clock::now() - t0);
- // but eventually, the LB sends a serverlist update that allows the call to
- // proceed. The call delay must be larger than the delay in sending the
- // populated serverlist but under the call's deadline (which is enforced by
- // the call's deadline).
- EXPECT_GT(ellapsed_ms.count(), kServerlistDelayMs);
- delayed_resource_setter.join();
- }
- // Tests that RPCs will fail with UNAVAILABLE instead of DEADLINE_EXCEEDED if
- // all the servers are unreachable.
- TEST_P(BasicTest, AllServersUnreachableFailFast) {
- // Set Rpc timeout to 5 seconds to ensure there is enough time
- // for communication with the xDS server to take place upon test start up.
- const uint32_t kRpcTimeoutMs = 5000;
- const size_t kNumUnreachableServers = 5;
- std::vector<EdsResourceArgs::Endpoint> endpoints;
- for (size_t i = 0; i < kNumUnreachableServers; ++i) {
- endpoints.emplace_back(grpc_pick_unused_port_or_die());
- }
- EdsResourceArgs args({
- {"locality0", endpoints},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const Status status = SendRpc(RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- // The error shouldn't be DEADLINE_EXCEEDED because timeout is set to 5
- // seconds, and we should disocver in that time that the target backend is
- // down.
- EXPECT_EQ(StatusCode::UNAVAILABLE, status.error_code());
- }
- // Tests that RPCs fail when the backends are down, and will succeed again
- // after the backends are restarted.
- TEST_P(BasicTest, BackendsRestart) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- // Stop backends. RPCs should fail.
- ShutdownAllBackends();
- // Sending multiple failed requests instead of just one to ensure that the
- // client notices that all backends are down before we restart them. If we
- // didn't do this, then a single RPC could fail here due to the race
- // condition between the LB pick and the GOAWAY from the chosen backend
- // being shut down, which would not actually prove that the client noticed
- // that all of the backends are down. Then, when we send another request
- // below (which we expect to succeed), if the callbacks happen in the wrong
- // order, the same race condition could happen again due to the client not
- // yet having noticed that the backends were all down.
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_times(num_backends_));
- // Restart all backends. RPCs should start succeeding again.
- StartAllBackends();
- CheckRpcSendOk(1, RpcOptions().set_timeout_ms(2000).set_wait_for_ready(true));
- }
- TEST_P(BasicTest, IgnoresDuplicateUpdates) {
- const size_t kNumRpcsPerAddress = 100;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for all backends to come online.
- WaitForAllBackends();
- // Send kNumRpcsPerAddress RPCs per server, but send an EDS update in
- // between. If the update is not ignored, this will cause the
- // round_robin policy to see an update, which will randomly reset its
- // position in the address list.
- for (size_t i = 0; i < kNumRpcsPerAddress; ++i) {
- CheckRpcSendOk(2);
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk(2);
- }
- // Each backend should have gotten the right number of requests.
- for (size_t i = 1; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- }
- using XdsResolverOnlyTest = BasicTest;
- TEST_P(XdsResolverOnlyTest, ResourceTypeVersionPersistsAcrossStreamRestarts) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for backends to come online.
- WaitForAllBackends(0, 1);
- // Stop balancer.
- balancer_->Shutdown();
- // Tell balancer to require minimum version 1 for all resource types.
- balancer_->ads_service()->SetResourceMinVersion(kLdsTypeUrl, 1);
- balancer_->ads_service()->SetResourceMinVersion(kRdsTypeUrl, 1);
- balancer_->ads_service()->SetResourceMinVersion(kCdsTypeUrl, 1);
- balancer_->ads_service()->SetResourceMinVersion(kEdsTypeUrl, 1);
- // Update backend, just so we can be sure that the client has
- // reconnected to the balancer.
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args2));
- // Restart balancer.
- balancer_->Start();
- // Make sure client has reconnected.
- WaitForAllBackends(1, 2);
- }
- // Tests switching over from one cluster to another.
- TEST_P(XdsResolverOnlyTest, ChangeClusters) {
- const char* kNewClusterName = "new_cluster_name";
- const char* kNewEdsServiceName = "new_eds_service_name";
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for all backends to come online.
- WaitForAllBackends(0, 2);
- // Populate new EDS resource.
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 4)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsServiceName));
- // Populate new CDS resource.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Change RDS resource to point to new cluster.
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- // Wait for all new backends to be used.
- WaitForAllBackends(2, 4);
- }
- // Tests that we go into TRANSIENT_FAILURE if the Cluster disappears.
- TEST_P(XdsResolverOnlyTest, ClusterRemoved) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for all backends to come online.
- WaitForAllBackends();
- // Unset CDS resource.
- balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
- // Wait for RPCs to start failing.
- do {
- } while (SendRpc(RpcOptions(), nullptr).ok());
- // Make sure RPCs are still failing.
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_times(1000));
- // Make sure we ACK'ed the update.
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that we restart all xDS requests when we reestablish the ADS call.
- TEST_P(XdsResolverOnlyTest, RestartsRequestsUponReconnection) {
- // Manually configure use of RDS.
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(kDefaultRouteConfigurationName);
- rds->mutable_config_source()->mutable_self();
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- balancer_->ads_service()->SetLdsResource(listener);
- balancer_->ads_service()->SetRdsResource(default_route_config_);
- const char* kNewClusterName = "new_cluster_name";
- const char* kNewEdsServiceName = "new_eds_service_name";
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for all backends to come online.
- WaitForAllBackends(0, 2);
- // Now shut down and restart the balancer. When the client
- // reconnects, it should automatically restart the requests for all
- // resource types.
- balancer_->Shutdown();
- balancer_->Start();
- // Make sure things are still working.
- CheckRpcSendOk(100);
- // Populate new EDS resource.
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 4)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsServiceName));
- // Populate new CDS resource.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Change RDS resource to point to new cluster.
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- balancer_->ads_service()->SetRdsResource(new_route_config);
- // Wait for all new backends to be used.
- WaitForAllBackends(2, 4);
- }
- TEST_P(XdsResolverOnlyTest, DefaultRouteSpecifiesSlashPrefix) {
- RouteConfiguration route_config = default_route_config_;
- route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_match()
- ->set_prefix("/");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for all backends to come online.
- WaitForAllBackends();
- }
- TEST_P(XdsResolverOnlyTest, CircuitBreaking) {
- constexpr size_t kMaxConcurrentRequests = 10;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Update CDS resource to set max concurrent request.
- CircuitBreakers circuit_breaks;
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Send exactly max_concurrent_requests long RPCs.
- LongRunningRpc rpcs[kMaxConcurrentRequests];
- for (size_t i = 0; i < kMaxConcurrentRequests; ++i) {
- rpcs[i].StartRpc(stub_.get());
- }
- // Wait for all RPCs to be in flight.
- while (backends_[0]->backend_service()->RpcsWaitingForClientCancel() <
- kMaxConcurrentRequests) {
- gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_micros(1 * 1000, GPR_TIMESPAN)));
- }
- // Sending a RPC now should fail, the error message should tell us
- // we hit the max concurrent requests limit and got dropped.
- Status status = SendRpc();
- EXPECT_FALSE(status.ok());
- EXPECT_EQ(status.error_message(), "circuit breaker drop");
- // Cancel one RPC to allow another one through
- rpcs[0].CancelRpc();
- status = SendRpc();
- EXPECT_TRUE(status.ok());
- for (size_t i = 1; i < kMaxConcurrentRequests; ++i) {
- rpcs[i].CancelRpc();
- }
- // Make sure RPCs go to the correct backend:
- EXPECT_EQ(kMaxConcurrentRequests + 1,
- backends_[0]->backend_service()->request_count());
- }
- TEST_P(XdsResolverOnlyTest, CircuitBreakingMultipleChannelsShareCallCounter) {
- constexpr size_t kMaxConcurrentRequests = 10;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Update CDS resource to set max concurrent request.
- CircuitBreakers circuit_breaks;
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto channel2 = CreateChannel();
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- // Send exactly max_concurrent_requests long RPCs, alternating between
- // the two channels.
- LongRunningRpc rpcs[kMaxConcurrentRequests];
- for (size_t i = 0; i < kMaxConcurrentRequests; ++i) {
- rpcs[i].StartRpc(i % 2 == 0 ? stub_.get() : stub2.get());
- }
- // Wait for all RPCs to be in flight.
- while (backends_[0]->backend_service()->RpcsWaitingForClientCancel() <
- kMaxConcurrentRequests) {
- gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_micros(1 * 1000, GPR_TIMESPAN)));
- }
- // Sending a RPC now should fail, the error message should tell us
- // we hit the max concurrent requests limit and got dropped.
- Status status = SendRpc();
- EXPECT_FALSE(status.ok());
- EXPECT_EQ(status.error_message(), "circuit breaker drop");
- // Cancel one RPC to allow another one through
- rpcs[0].CancelRpc();
- status = SendRpc();
- EXPECT_TRUE(status.ok());
- for (size_t i = 1; i < kMaxConcurrentRequests; ++i) {
- rpcs[i].CancelRpc();
- }
- // Make sure RPCs go to the correct backend:
- EXPECT_EQ(kMaxConcurrentRequests + 1,
- backends_[0]->backend_service()->request_count());
- }
- TEST_P(XdsResolverOnlyTest, ClusterChangeAfterAdsCallFails) {
- const char* kNewEdsResourceName = "new_eds_resource_name";
- // Populate EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Check that the channel is working.
- CheckRpcSendOk();
- // Stop and restart the balancer.
- balancer_->Shutdown();
- balancer_->Start();
- // Create new EDS resource.
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsResourceName));
- // Change CDS resource to point to new EDS resource.
- auto cluster = default_cluster_;
- cluster.mutable_eds_cluster_config()->set_service_name(kNewEdsResourceName);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Make sure client sees the change.
- // TODO(roth): This should not be allowing errors. The errors are
- // being caused by a bug that triggers in the following situation:
- //
- // 1. xDS call fails.
- // 2. When xDS call is restarted, the server sends the updated CDS
- // resource that points to the new EDS resource name.
- // 3. When the client receives the CDS update, it does two things:
- // - Sends the update to the CDS LB policy, which creates a new
- // xds_cluster_resolver policy using the new EDS service name.
- // - Notices that the CDS update no longer refers to the old EDS
- // service name, so removes that resource, notifying the old
- // xds_cluster_resolver policy that the resource no longer exists.
- //
- // Need to figure out a way to fix this bug, and then change this to
- // not allow failures.
- WaitForBackend(1, WaitForBackendOptions().set_allow_failures(true));
- }
- // Tests that if the balancer is down, the RPCs will still be sent to the
- // backends according to the last balancer response, until a new balancer is
- // reachable.
- TEST_P(XdsResolverOnlyTest, KeepUsingLastDataIfBalancerGoesDown) {
- // Set up EDS resource pointing to backend 0.
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Start the client and make sure it sees the backend.
- WaitForBackend(0);
- // Stop the balancer, and verify that RPCs continue to flow to backend 0.
- balancer_->Shutdown();
- auto deadline = grpc_timeout_seconds_to_deadline(5);
- do {
- CheckRpcSendOk();
- } while (gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
- // Check the EDS resource to point to backend 1 and bring the balancer
- // back up.
- args = EdsResourceArgs({{"locality0", CreateEndpointsForBackends(1, 2)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->Start();
- // Wait for client to see backend 1.
- WaitForBackend(1);
- }
- TEST_P(XdsResolverOnlyTest, XdsStreamErrorPropagation) {
- const std::string kErrorMessage = "test forced ADS stream failure";
- balancer_->ads_service()->ForceADSFailure(
- Status(StatusCode::RESOURCE_EXHAUSTED, kErrorMessage));
- auto status = SendRpc();
- gpr_log(GPR_INFO,
- "XdsStreamErrorPropagation test: RPC got error: code=%d message=%s",
- status.error_code(), status.error_message().c_str());
- EXPECT_THAT(status.error_code(), StatusCode::UNAVAILABLE);
- EXPECT_THAT(status.error_message(), ::testing::HasSubstr(kErrorMessage));
- }
- using GlobalXdsClientTest = BasicTest;
- TEST_P(GlobalXdsClientTest, MultipleChannelsShareXdsClient) {
- const char* kNewServerName = "new-server.example.com";
- Listener listener = default_listener_;
- listener.set_name(kNewServerName);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- // Create second channel and tell it to connect to kNewServerName.
- auto channel2 = CreateChannel(/*failover_timeout=*/0, kNewServerName);
- channel2->GetState(/*try_to_connect=*/true);
- ASSERT_TRUE(
- channel2->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100)));
- // Make sure there's only one client connected.
- EXPECT_EQ(1UL, balancer_->ads_service()->clients().size());
- }
- TEST_P(
- GlobalXdsClientTest,
- MultipleChannelsShareXdsClientWithResourceUpdateAfterOneChannelGoesAway) {
- // Test for https://github.com/grpc/grpc/issues/28468. Makes sure that the
- // XdsClient properly handles the case where there are multiple watchers on
- // the same resource and one of them unsubscribes.
- const char* kNewServerName = "new-server.example.com";
- Listener listener = default_listener_;
- listener.set_name(kNewServerName);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- })));
- WaitForBackend(0);
- // Create second channel and tell it to connect to kNewServerName.
- auto channel2 = CreateChannel(/*failover_timeout=*/0, kNewServerName);
- channel2->GetState(/*try_to_connect=*/true);
- ASSERT_TRUE(
- channel2->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100)));
- // Now, destroy the new channel, send an EDS update to use a different backend
- // and test that the channel switches to that backend.
- channel2.reset();
- // This sleep is needed to be able to reproduce the bug and to give time for
- // the buggy unsubscription to take place.
- // TODO(yashykt): Figure out a way to do this without the sleep.
- gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(10));
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- })));
- WaitForBackend(1);
- }
- // Tests that the NACK for multiple bad LDS resources includes both errors.
- TEST_P(GlobalXdsClientTest, MultipleBadResources) {
- constexpr char kServerName2[] = "server.other.com";
- constexpr char kServerName3[] = "server.another.com";
- auto listener = default_listener_;
- listener.clear_api_listener();
- balancer_->ads_service()->SetLdsResource(listener);
- listener.set_name(kServerName2);
- balancer_->ads_service()->SetLdsResource(listener);
- listener = default_listener_;
- listener.set_name(kServerName3);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(
- kServerName,
- ": validation error.*"
- "Listener has neither address nor ApiListener.*")));
- // Need to create a second channel to subscribe to a second LDS resource.
- auto channel2 = CreateChannel(0, kServerName2);
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- {
- ClientContext context;
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- grpc::Status status = stub2->Echo(&context, request, &response);
- EXPECT_FALSE(status.ok());
- // Wait for second NACK to be reported to xDS server.
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(
- kServerName,
- ": validation error.*"
- "Listener has neither address nor ApiListener.*")));
- EXPECT_THAT(response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(
- kServerName2,
- ": validation error.*"
- "Listener has neither address nor ApiListener.*")));
- }
- // Now start a new channel with a third server name, this one with a
- // valid resource.
- auto channel3 = CreateChannel(0, kServerName3);
- auto stub3 = grpc::testing::EchoTestService::NewStub(channel3);
- {
- ClientContext context;
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- grpc::Status status = stub3->Echo(&context, request, &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- }
- // Tests that we don't trigger does-not-exist callbacks for a resource
- // that was previously valid but is updated to be invalid.
- TEST_P(GlobalXdsClientTest, InvalidListenerStillExistsIfPreviouslyCached) {
- // Set up valid resources and check that the channel works.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk();
- // Now send an update changing the Listener to be invalid.
- auto listener = default_listener_;
- listener.clear_api_listener();
- balancer_->ads_service()->SetLdsResource(listener);
- const auto response_state = WaitForLdsNack(StatusCode::OK);
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(
- kServerName,
- ": validation error.*"
- "Listener has neither address nor ApiListener")));
- }
- class XdsFederationTest : public XdsEnd2endTest {
- protected:
- XdsFederationTest() : XdsEnd2endTest(2, 3, 0, true) {
- authority_balancer_ = CreateAndStartBalancer();
- }
- void SetUp() override {
- // Each test will use a slightly different bootstrapfile,
- // so SetUp() is intentionally empty here and the real
- // setup: calling of CreateClientAndServers(builder)
- // is moved into each test.
- }
- void TearDown() override {
- authority_balancer_->Shutdown();
- XdsEnd2endTest::TearDown();
- }
- std::unique_ptr<BalancerServerThread> authority_balancer_;
- };
- // Channel is created with URI "xds:server.example.com".
- // Bootstrap config default client listener template uses new-style name with
- // authority "xds.example.com".
- TEST_P(XdsFederationTest, FederationTargetNoAuthorityWithResourceTemplate) {
- gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
- const char* kAuthority = "xds.example.com";
- const char* kNewListenerTemplate =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/%s?psm_project_id=1234";
- const char* kNewListenerName =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/server.example.com?psm_project_id=1234";
- const char* kNewRouteConfigName =
- "xdstp://xds.example.com/envoy.config.route.v3.RouteConfiguration/"
- "new_route_config_name";
- const char* kNewEdsServiceName =
- "xdstp://xds.example.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
- "new_edsservice_name";
- const char* kNewClusterName =
- "xdstp://xds.example.com/envoy.config.cluster.v3.Cluster/"
- "new_cluster_name";
- BootstrapBuilder builder = BootstrapBuilder();
- builder.SetClientDefaultListenerResourceNameTemplate(kNewListenerTemplate);
- builder.AddAuthority(
- kAuthority, absl::StrCat("localhost:", authority_balancer_->port()),
- // Note we will not use the client_listener_resource_name_template field
- // in the authority.
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener"
- "client/%s?client_listener_resource_name_template_not_in_use");
- CreateClientsAndServers(builder);
- StartAllBackends();
- // Eds for the new authority balancer.
- EdsResourceArgs args =
- EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}});
- authority_balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kNewEdsServiceName));
- // New cluster
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- authority_balancer_->ads_service()->SetCdsResource(new_cluster);
- // New Route
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.set_name(kNewRouteConfigName);
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- // New Listener
- Listener listener = default_listener_;
- listener.set_name(kNewListenerName);
- SetListenerAndRouteConfiguration(authority_balancer_.get(), listener,
- new_route_config);
- WaitForAllBackends();
- gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
- }
- // Channel is created with URI "xds://xds.example.com/server.example.com".
- // In bootstrap config, authority has no client listener template, so we use the
- // default.
- TEST_P(XdsFederationTest, FederationTargetAuthorityDefaultResourceTemplate) {
- gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
- const char* kAuthority = "xds.example.com";
- const char* kNewServerName = "whee%/server.example.com";
- const char* kNewListenerName =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "whee%25/server.example.com";
- const char* kNewRouteConfigName =
- "xdstp://xds.example.com/envoy.config.route.v3.RouteConfiguration/"
- "new_route_config_name";
- const char* kNewEdsServiceName =
- "xdstp://xds.example.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
- "edsservice_name";
- const char* kNewClusterName =
- "xdstp://xds.example.com/envoy.config.cluster.v3.Cluster/"
- "cluster_name";
- BootstrapBuilder builder = BootstrapBuilder();
- builder.AddAuthority(kAuthority,
- absl::StrCat("localhost:", authority_balancer_->port()));
- CreateClientsAndServers(builder);
- StartAllBackends();
- // Eds for 2 balancers to ensure RPCs sent using current stub go to backend 0
- // and RPCs sent using the new stub go to backend 1.
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({{"locality0", CreateEndpointsForBackends(1, 2)}});
- authority_balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kNewEdsServiceName));
- // New cluster
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- authority_balancer_->ads_service()->SetCdsResource(new_cluster);
- // New Route
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.set_name(kNewRouteConfigName);
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- // New Listener
- Listener listener = default_listener_;
- listener.set_name(kNewListenerName);
- SetListenerAndRouteConfiguration(authority_balancer_.get(), listener,
- new_route_config);
- // Ensure update has reached and send 10 RPCs to the current stub.
- WaitForAllBackends(0, 1);
- // Create second channel to new target uri and send 1 RPC .
- auto channel2 =
- CreateChannel(/*failover_timeout=*/0, kNewServerName, kAuthority);
- channel2->GetState(/*try_to_connect=*/true);
- ASSERT_TRUE(
- channel2->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100)));
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- ClientContext context;
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- grpc::Status status = stub2->Echo(&context, request, &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- // We should be reaching backend 1, not 0, as balanced by the authority xds
- // server.
- EXPECT_EQ(0U, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(1U, backends_[1]->backend_service()->request_count());
- gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
- }
- // Channel is created with URI "xds://xds.example.com/server.example.com".
- // Bootstrap entry for that authority specifies a client listener name template.
- TEST_P(XdsFederationTest, FederationTargetAuthorityWithResourceTemplate) {
- gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
- const char* kAuthority = "xds.example.com";
- const char* kNewServerName = "whee%/server.example.com";
- const char* kNewListenerTemplate =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/%s?psm_project_id=1234";
- const char* kNewListenerName =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/whee%25/server.example.com?psm_project_id=1234";
- const char* kNewRouteConfigName =
- "xdstp://xds.example.com/envoy.config.route.v3.RouteConfiguration/"
- "new_route_config_name";
- const char* kNewEdsServiceName =
- "xdstp://xds.example.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
- "edsservice_name";
- const char* kNewClusterName =
- "xdstp://xds.example.com/envoy.config.cluster.v3.Cluster/"
- "cluster_name";
- BootstrapBuilder builder = BootstrapBuilder();
- builder.AddAuthority(kAuthority,
- absl::StrCat("localhost:", authority_balancer_->port()),
- kNewListenerTemplate);
- CreateClientsAndServers(builder);
- StartAllBackends();
- // Eds for 2 balancers to ensure RPCs sent using current stub go to backend 0
- // and RPCs sent using the new stub go to backend 1.
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({{"locality0", CreateEndpointsForBackends(1, 2)}});
- authority_balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kNewEdsServiceName));
- // New cluster
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- authority_balancer_->ads_service()->SetCdsResource(new_cluster);
- // New Route
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.set_name(kNewRouteConfigName);
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- // New Listener
- Listener listener = default_listener_;
- listener.set_name(kNewListenerName);
- SetListenerAndRouteConfiguration(authority_balancer_.get(), listener,
- new_route_config);
- // Ensure update has reached and send 10 RPCs to the current stub.
- WaitForAllBackends(0, 1);
- // Create second channel to new target uri and send 1 RPC .
- auto channel2 =
- CreateChannel(/*failover_timeout=*/0, kNewServerName, kAuthority);
- channel2->GetState(/*try_to_connect=*/true);
- ASSERT_TRUE(
- channel2->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100)));
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- ClientContext context;
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- grpc::Status status = stub2->Echo(&context, request, &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- // We should be reaching backend 1, not 0, as balanced by the authority xds
- // server.
- EXPECT_EQ(0U, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(1U, backends_[1]->backend_service()->request_count());
- gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
- }
- // Setting server_listener_resource_name_template to start with "xdstp:" and
- // look up xds server under an authority map.
- TEST_P(XdsFederationTest, FederationServer) {
- gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
- const char* kAuthority = "xds.example.com";
- const char* kNewListenerTemplate =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/%s?psm_project_id=1234";
- const char* kNewServerListenerTemplate =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "server/%s?psm_project_id=1234";
- const char* kNewListenerName =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/server.example.com?psm_project_id=1234";
- const char* kNewRouteConfigName =
- "xdstp://xds.example.com/envoy.config.route.v3.RouteConfiguration/"
- "new_route_config_name";
- const char* kNewEdsServiceName =
- "xdstp://xds.example.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
- "new_edsservice_name";
- const char* kNewClusterName =
- "xdstp://xds.example.com/envoy.config.cluster.v3.Cluster/"
- "new_cluster_name";
- BootstrapBuilder builder = BootstrapBuilder();
- builder.SetClientDefaultListenerResourceNameTemplate(kNewListenerTemplate);
- builder.SetServerListenerResourceNameTemplate(kNewServerListenerTemplate);
- builder.AddAuthority(
- kAuthority, absl::StrCat("localhost:", authority_balancer_->port()),
- // Note we will not use the client_listener_resource_name_template field
- // in the authority.
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener"
- "client/%s?client_listener_resource_name_template_not_in_use");
- CreateClientsAndServers(builder);
- StartAllBackends();
- // Eds for new authority balancer.
- EdsResourceArgs args =
- EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}});
- authority_balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kNewEdsServiceName));
- // New cluster
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- authority_balancer_->ads_service()->SetCdsResource(new_cluster);
- // New Route
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.set_name(kNewRouteConfigName);
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- // New Listener
- Listener listener = default_listener_;
- listener.set_name(kNewListenerName);
- SetListenerAndRouteConfiguration(authority_balancer_.get(), listener,
- new_route_config);
- // New Server Listeners
- for (int port : GetBackendPorts()) {
- Listener server_listener = default_server_listener_;
- server_listener.set_name(absl::StrCat(
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/server/",
- ipv6_only_ ? "%5B::1%5D:" : "127.0.0.1:", port,
- "?psm_project_id=1234"));
- server_listener.mutable_address()->mutable_socket_address()->set_port_value(
- port);
- authority_balancer_->ads_service()->SetLdsResource(server_listener);
- }
- WaitForAllBackends();
- gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
- }
- using XdsFederationLoadReportingTest = XdsFederationTest;
- // Channel is created with URI "xds://xds.example.com/server.example.com".
- // Bootstrap entry for that authority specifies a client listener name template.
- // Sending traffic to both default balancer and authority balancer and checking
- // load reporting with each one.
- TEST_P(XdsFederationLoadReportingTest, FederationMultipleLoadReportingTest) {
- gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
- const char* kAuthority = "xds.example.com";
- const char* kNewServerName = "whee%/server.example.com";
- const char* kNewListenerTemplate =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/%s?psm_project_id=1234";
- const char* kNewListenerName =
- "xdstp://xds.example.com/envoy.config.listener.v3.Listener/"
- "client/whee%25/server.example.com?psm_project_id=1234";
- const char* kNewRouteConfigName =
- "xdstp://xds.example.com/envoy.config.route.v3.RouteConfiguration/"
- "new_route_config_name";
- const char* kNewEdsServiceName =
- "xdstp://xds.example.com/envoy.config.endpoint.v3.ClusterLoadAssignment/"
- "edsservice_name";
- const char* kNewClusterName =
- "xdstp://xds.example.com/envoy.config.cluster.v3.Cluster/"
- "cluster_name";
- const size_t kNumRpcsToDefaultBalancer = 5;
- const size_t kNumRpcsToAuthorityBalancer = 10;
- BootstrapBuilder builder = BootstrapBuilder();
- builder.AddAuthority(kAuthority,
- absl::StrCat("localhost:", authority_balancer_->port()),
- kNewListenerTemplate);
- CreateClientsAndServers(builder);
- StartAllBackends();
- // Eds for 2 balancers to ensure RPCs sent using current stub go to backend 0
- // and RPCs sent using the new stub go to backend 1.
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({{"locality0", CreateEndpointsForBackends(1, 2)}});
- authority_balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kNewEdsServiceName));
- authority_balancer_->lrs_service()->set_cluster_names({kNewClusterName});
- // New cluster
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_lrs_server()->mutable_self();
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- authority_balancer_->ads_service()->SetCdsResource(new_cluster);
- // New Route
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.set_name(kNewRouteConfigName);
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- // New Listener
- Listener listener = default_listener_;
- listener.set_name(kNewListenerName);
- SetListenerAndRouteConfiguration(authority_balancer_.get(), listener,
- new_route_config);
- // Ensure update has reached and send 10 RPCs to the current stub.
- CheckRpcSendOk(kNumRpcsToDefaultBalancer);
- // Create second channel to new target uri and send 1 RPC .
- auto channel2 =
- CreateChannel(/*failover_timeout=*/0, kNewServerName, kAuthority);
- channel2->GetState(/*try_to_connect=*/true);
- ASSERT_TRUE(
- channel2->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100)));
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- for (size_t i = 0; i < kNumRpcsToAuthorityBalancer; ++i) {
- ClientContext context;
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- grpc::Status status = stub2->Echo(&context, request, &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- // Each backend should have received the expected number of RPCs,
- // and the load report also reflect the correct numbers.
- EXPECT_EQ(kNumRpcsToAuthorityBalancer,
- backends_[1]->backend_service()->request_count());
- EXPECT_EQ(kNumRpcsToDefaultBalancer,
- backends_[0]->backend_service()->request_count());
- // Load report for authority LRS.
- std::vector<ClientStats> authority_load_report =
- authority_balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(authority_load_report.size(), 1UL);
- ClientStats& authority_client_stats = authority_load_report.front();
- EXPECT_EQ(kNumRpcsToAuthorityBalancer,
- authority_client_stats.total_successful_requests());
- EXPECT_EQ(0U, authority_client_stats.total_requests_in_progress());
- EXPECT_EQ(kNumRpcsToAuthorityBalancer,
- authority_client_stats.total_issued_requests());
- EXPECT_EQ(0U, authority_client_stats.total_error_requests());
- EXPECT_EQ(0U, authority_client_stats.total_dropped_requests());
- EXPECT_EQ(1U, authority_balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, authority_balancer_->lrs_service()->response_count());
- // Load report for default LRS.
- std::vector<ClientStats> default_load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(default_load_report.size(), 1UL);
- ClientStats& default_client_stats = default_load_report.front();
- EXPECT_EQ(kNumRpcsToDefaultBalancer,
- default_client_stats.total_successful_requests());
- EXPECT_EQ(0U, default_client_stats.total_requests_in_progress());
- EXPECT_EQ(kNumRpcsToDefaultBalancer,
- default_client_stats.total_issued_requests());
- EXPECT_EQ(0U, default_client_stats.total_error_requests());
- EXPECT_EQ(0U, default_client_stats.total_dropped_requests());
- EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
- gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
- }
- class SecureNamingTest : public XdsEnd2endTest {
- public:
- SecureNamingTest()
- : XdsEnd2endTest(/*num_backends=*/4,
- /*client_load_reporting_interval_seconds=*/100,
- /*xds_resource_does_not_exist_timeout_ms=*/0,
- /*use_xds_enabled_server=*/false) {}
- void SetUp() override {}
- };
- // Tests that secure naming check passes if target name is expected.
- TEST_P(SecureNamingTest, TargetNameIsExpected) {
- CreateClientsAndServers(BootstrapBuilder(),
- /*lb_expected_authority=*/"localhost:%d");
- StartAllBackends();
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk();
- }
- // Tests that secure naming check fails if target name is unexpected.
- TEST_P(SecureNamingTest, TargetNameIsUnexpected) {
- GTEST_FLAG_SET(death_test_style, "threadsafe");
- CreateClientsAndServers(BootstrapBuilder(),
- /*lb_expected_authority=*/"incorrect_server_name");
- StartAllBackends();
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Make sure that we blow up (via abort() from the security connector) when
- // the name from the balancer doesn't match expectations.
- ASSERT_DEATH_IF_SUPPORTED({ CheckRpcSendOk(); }, "");
- }
- using LdsTest = BasicTest;
- // Tests that LDS client should send a NACK if there is no API listener in the
- // Listener in the LDS response.
- TEST_P(LdsTest, NoApiListener) {
- auto listener = default_listener_;
- listener.clear_api_listener();
- balancer_->ads_service()->SetLdsResource(listener);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Listener has neither address nor ApiListener"));
- }
- // Tests that LDS client should send a NACK if the route_specifier in the
- // http_connection_manager is neither inlined route_config nor RDS.
- TEST_P(LdsTest, WrongRouteSpecifier) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- http_connection_manager.mutable_scoped_routes();
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- balancer_->ads_service()->SetLdsResource(listener);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "HttpConnectionManager neither has inlined route_config nor RDS."));
- }
- // Tests that LDS client should send a NACK if the rds message in the
- // http_connection_manager is missing the config_source field.
- TEST_P(LdsTest, RdsMissingConfigSource) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- http_connection_manager.mutable_rds()->set_route_config_name(
- kDefaultRouteConfigurationName);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- balancer_->ads_service()->SetLdsResource(listener);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "HttpConnectionManager missing config_source for RDS."));
- }
- // Tests that LDS client should send a NACK if the rds message in the
- // http_connection_manager has a config_source field that does not specify
- // ADS or SELF.
- TEST_P(LdsTest, RdsConfigSourceDoesNotSpecifyAdsOrSelf) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(kDefaultRouteConfigurationName);
- rds->mutable_config_source()->set_path("/foo/bar");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- balancer_->ads_service()->SetLdsResource(listener);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("HttpConnectionManager ConfigSource for "
- "RDS does not specify ADS or SELF."));
- }
- // Tests that LDS client accepts the rds message in the
- // http_connection_manager with a config_source field that specifies ADS.
- TEST_P(LdsTest, AcceptsRdsConfigSourceOfTypeAds) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(kDefaultRouteConfigurationName);
- rds->mutable_config_source()->mutable_ads();
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that we NACK non-terminal filters at the end of the list.
- TEST_P(LdsTest, NacksNonTerminalHttpFilterAtEndOfList) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("unknown");
- filter->mutable_typed_config()->set_type_url(
- "grpc.testing.client_only_http_filter");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "non-terminal filter for config type grpc.testing"
- ".client_only_http_filter is the last filter in the chain"));
- }
- // Test that we NACK terminal filters that are not at the end of the list.
- TEST_P(LdsTest, NacksTerminalFilterBeforeEndOfList) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- // The default_listener_ has a terminal router filter by default. Add an
- // additional filter.
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("grpc.testing.terminal_http_filter");
- filter->mutable_typed_config()->set_type_url(
- "grpc.testing.terminal_http_filter");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "terminal filter for config type envoy.extensions.filters.http"
- ".router.v3.Router must be the last filter in the chain"));
- }
- // Test that we NACK empty filter names.
- TEST_P(LdsTest, RejectsEmptyHttpFilterName) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->Clear();
- filter->mutable_typed_config()->PackFrom(Listener());
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("empty filter name at index 0"));
- }
- // Test that we NACK duplicate HTTP filter names.
- TEST_P(LdsTest, RejectsDuplicateHttpFilterName) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- http_connection_manager.mutable_http_filters(0)
- ->mutable_typed_config()
- ->PackFrom(HTTPFault());
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("duplicate HTTP filter name: router"));
- }
- // Test that we NACK unknown filter types.
- TEST_P(LdsTest, RejectsUnknownHttpFilterType) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("unknown");
- filter->mutable_typed_config()->PackFrom(Listener());
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("no filter registered for config type "
- "envoy.config.listener.v3.Listener"));
- }
- // Test that we ignore optional unknown filter types.
- TEST_P(LdsTest, IgnoresOptionalUnknownHttpFilterType) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("unknown");
- filter->mutable_typed_config()->PackFrom(Listener());
- filter->set_is_optional(true);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK filters without configs.
- TEST_P(LdsTest, RejectsHttpFilterWithoutConfig) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->Clear();
- filter->set_name("unknown");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we ignore optional filters without configs.
- TEST_P(LdsTest, IgnoresOptionalHttpFilterWithoutConfig) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->Clear();
- filter->set_name("unknown");
- filter->set_is_optional(true);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK unparseable filter configs.
- TEST_P(LdsTest, RejectsUnparseableHttpFilterType) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("unknown");
- filter->mutable_typed_config()->PackFrom(listener);
- filter->mutable_typed_config()->set_type_url(
- "type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "filter config for type "
- "envoy.extensions.filters.http.fault.v3.HTTPFault failed to parse"));
- }
- // Test that we NACK HTTP filters unsupported on client-side.
- TEST_P(LdsTest, RejectsHttpFiltersNotSupportedOnClients) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("grpc.testing.server_only_http_filter");
- filter->mutable_typed_config()->set_type_url(
- "grpc.testing.server_only_http_filter");
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Filter grpc.testing.server_only_http_filter is not "
- "supported on clients"));
- }
- // Test that we ignore optional HTTP filters unsupported on client-side.
- TEST_P(LdsTest, IgnoresOptionalHttpFiltersNotSupportedOnClients) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- *http_connection_manager.add_http_filters() =
- http_connection_manager.http_filters(0);
- auto* filter = http_connection_manager.mutable_http_filters(0);
- filter->set_name("grpc.testing.server_only_http_filter");
- filter->mutable_typed_config()->set_type_url(
- "grpc.testing.server_only_http_filter");
- filter->set_is_optional(true);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForBackend(0);
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK non-zero xff_num_trusted_hops
- TEST_P(LdsTest, RejectsNonZeroXffNumTrusterHops) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- http_connection_manager.set_xff_num_trusted_hops(1);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'xff_num_trusted_hops' must be zero"));
- }
- // Test that we NACK non-empty original_ip_detection_extensions
- TEST_P(LdsTest, RejectsNonEmptyOriginalIpDetectionExtensions) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- http_connection_manager.add_original_ip_detection_extensions();
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("'original_ip_detection_extensions' must be empty"));
- }
- using LdsV2Test = LdsTest;
- // Tests that we ignore the HTTP filter list in v2.
- // TODO(roth): The test framework is not set up to allow us to test
- // the server sending v2 resources when the client requests v3, so this
- // just tests a pure v2 setup. When we have time, fix this.
- TEST_P(LdsV2Test, IgnoresHttpFilters) {
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("unknown");
- filter->mutable_typed_config()->PackFrom(Listener());
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk();
- }
- using LdsRdsTest = BasicTest;
- MATCHER_P2(AdjustedClockInRange, t1, t2, "equals time") {
- gpr_cycle_counter cycle_now = gpr_get_cycle_counter();
- grpc_core::Timestamp cycle_time =
- grpc_core::Timestamp::FromCycleCounterRoundDown(cycle_now);
- grpc_core::Timestamp time_spec =
- grpc_core::Timestamp::FromTimespecRoundDown(gpr_now(GPR_CLOCK_MONOTONIC));
- grpc_core::Timestamp now = arg + (time_spec - cycle_time);
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(::testing::Ge(t1), now, result_listener);
- ok &= ::testing::ExplainMatchResult(::testing::Lt(t2), now, result_listener);
- return ok;
- }
- // Tests that LDS client should send an ACK upon correct LDS response (with
- // inlined RDS result).
- TEST_P(LdsRdsTest, Vanilla) {
- (void)SendRpc();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- // Make sure we actually used the RPC service for the right version of xDS.
- EXPECT_EQ(balancer_->ads_service()->seen_v2_client(), GetParam().use_v2());
- EXPECT_NE(balancer_->ads_service()->seen_v3_client(), GetParam().use_v2());
- }
- // Tests that we go into TRANSIENT_FAILURE if the Listener is removed.
- TEST_P(LdsRdsTest, ListenerRemoved) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // We need to wait for all backends to come online.
- WaitForAllBackends();
- // Unset LDS resource.
- balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
- // Wait for RPCs to start failing.
- do {
- } while (SendRpc(RpcOptions(), nullptr).ok());
- // Make sure RPCs are still failing.
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_times(1000));
- // Make sure we ACK'ed the update.
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that LDS client ACKs but fails if matching domain can't be found in
- // the LDS response.
- TEST_P(LdsRdsTest, NoMatchedDomain) {
- RouteConfiguration route_config = default_route_config_;
- route_config.mutable_virtual_hosts(0)->clear_domains();
- route_config.mutable_virtual_hosts(0)->add_domains("unmatched_domain");
- SetRouteConfiguration(balancer_.get(), route_config);
- CheckRpcSendFailure();
- // Do a bit of polling, to allow the ACK to get to the ADS server.
- channel_->WaitForConnected(grpc_timeout_milliseconds_to_deadline(100));
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that LDS client should choose the virtual host with matching domain
- // if multiple virtual hosts exist in the LDS response.
- TEST_P(LdsRdsTest, ChooseMatchedDomain) {
- RouteConfiguration route_config = default_route_config_;
- *(route_config.add_virtual_hosts()) = route_config.virtual_hosts(0);
- route_config.mutable_virtual_hosts(0)->clear_domains();
- route_config.mutable_virtual_hosts(0)->add_domains("unmatched_domain");
- SetRouteConfiguration(balancer_.get(), route_config);
- (void)SendRpc();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that LDS client should choose the last route in the virtual host if
- // multiple routes exist in the LDS response.
- TEST_P(LdsRdsTest, ChooseLastRoute) {
- RouteConfiguration route_config = default_route_config_;
- *(route_config.mutable_virtual_hosts(0)->add_routes()) =
- route_config.virtual_hosts(0).routes(0);
- route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_cluster_header();
- SetRouteConfiguration(balancer_.get(), route_config);
- (void)SendRpc();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that LDS client should ignore route which has query_parameters.
- TEST_P(LdsRdsTest, RouteMatchHasQueryParameters) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- route1->mutable_match()->add_query_parameters();
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should send a ACK if route match has a prefix
- // that is either empty or a single slash
- TEST_P(LdsRdsTest, RouteMatchHasValidPrefixEmptyOrSingleSlash) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("");
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("/");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- (void)SendRpc();
- const auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that LDS client should ignore route which has a path
- // prefix string does not start with "/".
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixNoLeadingSlash) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("grpc.testing.EchoTest1Service/");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has a prefix
- // string with more than 2 slashes.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixExtraContent) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/Echo1/");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has a prefix
- // string "//".
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPrefixDoubleSlash) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("//");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // but it's empty.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathEmptyPath) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // string does not start with "/".
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathNoLeadingSlash) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("grpc.testing.EchoTest1Service/Echo1");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // string that has too many slashes; for example, ends with "/".
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathTooManySlashes) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/Echo1/");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // string that has only 1 slash: missing "/" between service and method.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathOnlyOneSlash) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service.Echo1");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // string that is missing service.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingService) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("//Echo1");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Tests that LDS client should ignore route which has path
- // string that is missing method.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathMissingMethod) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/");
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No valid routes specified."));
- }
- // Test that LDS client should reject route which has invalid path regex.
- TEST_P(LdsRdsTest, RouteMatchHasInvalidPathRegex) {
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->mutable_safe_regex()->set_regex("a[z-a]");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "path matcher: Invalid regex string specified in matcher."));
- }
- // Tests that LDS client should fail RPCs with UNAVAILABLE status code if the
- // matching route has an action other than RouteAction.
- TEST_P(LdsRdsTest, MatchingRouteHasNoRouteAction) {
- RouteConfiguration route_config = default_route_config_;
- // Set a route with an inappropriate route action
- auto* vhost = route_config.mutable_virtual_hosts(0);
- vhost->mutable_routes(0)->mutable_redirect();
- // Add another route to make sure that the resolver code actually tries to
- // match to a route instead of using a shorthand logic to error out.
- auto* route = vhost->add_routes();
- route->mutable_match()->set_prefix("");
- route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_expected_error_code(
- StatusCode::UNAVAILABLE));
- }
- TEST_P(LdsRdsTest, RouteActionClusterHasEmptyClusterName) {
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- route1->mutable_route()->set_cluster("");
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("RouteAction cluster contains empty cluster name."));
- }
- TEST_P(LdsRdsTest, RouteActionWeightedTargetHasIncorrectTotalWeightSet) {
- const size_t kWeight75 = 75;
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75 + 1);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "RouteAction weighted_cluster has incorrect total weight"));
- }
- TEST_P(LdsRdsTest, RouteActionWeightedClusterHasZeroTotalWeight) {
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(0);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(0);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "RouteAction weighted_cluster has no valid clusters specified."));
- }
- TEST_P(LdsRdsTest, RouteActionWeightedTargetClusterHasEmptyClusterName) {
- const size_t kWeight75 = 75;
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name("");
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("RouteAction weighted_cluster cluster "
- "contains empty cluster name."));
- }
- TEST_P(LdsRdsTest, RouteActionWeightedTargetClusterHasNoWeight) {
- const size_t kWeight75 = 75;
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "RouteAction weighted_cluster cluster missing weight"));
- }
- TEST_P(LdsRdsTest, RouteHeaderMatchInvalidRegex) {
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("header1");
- header_matcher1->mutable_safe_regex_match()->set_regex("a[z-a]");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "header matcher: Invalid regex string specified in matcher."));
- }
- TEST_P(LdsRdsTest, RouteHeaderMatchInvalidRange) {
- const char* kNewCluster1Name = "new_cluster_1";
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("header1");
- header_matcher1->mutable_range_match()->set_start(1001);
- header_matcher1->mutable_range_match()->set_end(1000);
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- SetRouteConfiguration(balancer_.get(), route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "header matcher: Invalid range specifier specified: end cannot be "
- "smaller than start."));
- }
- // Tests that LDS client should choose the default route (with no matching
- // specified) after unable to find a match with previous routes.
- TEST_P(LdsRdsTest, XdsRoutingPathMatching) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kNumEcho1Rpcs = 10;
- const size_t kNumEcho2Rpcs = 20;
- const size_t kNumEchoRpcs = 30;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/Echo1");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_path("/grpc.testing.EchoTest2Service/Echo2");
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto* route3 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route3->mutable_match()->set_path("/grpc.testing.EchoTest3Service/Echo3");
- route3->mutable_route()->set_cluster(kDefaultClusterName);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 2);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_wait_for_ready(true));
- CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_wait_for_ready(true));
- CheckRpcSendOk(kNumEcho2Rpcs, RpcOptions()
- .set_rpc_service(SERVICE_ECHO2)
- .set_rpc_method(METHOD_ECHO2)
- .set_wait_for_ready(true));
- // Make sure RPCs all go to the correct backend.
- for (size_t i = 0; i < 2; ++i) {
- EXPECT_EQ(kNumEchoRpcs / 2,
- backends_[i]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service2()->request_count());
- }
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[2]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service2()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- EXPECT_EQ(kNumEcho2Rpcs, backends_[3]->backend_service2()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingPathMatchingCaseInsensitive) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kNumEcho1Rpcs = 10;
- const size_t kNumEchoRpcs = 30;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- // First route will not match, since it's case-sensitive.
- // Second route will match with same path.
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/GrPc.TeStInG.EcHoTeSt1SErViCe/EcHo1");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_path("/GrPc.TeStInG.EcHoTeSt1SErViCe/EcHo1");
- route2->mutable_match()->mutable_case_sensitive()->set_value(false);
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_wait_for_ready(true));
- CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_wait_for_ready(true));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[2]->backend_service1()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingPrefixMatching) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kNumEcho1Rpcs = 10;
- const size_t kNumEcho2Rpcs = 20;
- const size_t kNumEchoRpcs = 30;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_prefix("/grpc.testing.EchoTest2Service/");
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 2);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_wait_for_ready(true));
- CheckRpcSendOk(
- kNumEcho1Rpcs,
- RpcOptions().set_rpc_service(SERVICE_ECHO1).set_wait_for_ready(true));
- CheckRpcSendOk(
- kNumEcho2Rpcs,
- RpcOptions().set_rpc_service(SERVICE_ECHO2).set_wait_for_ready(true));
- // Make sure RPCs all go to the correct backend.
- for (size_t i = 0; i < 2; ++i) {
- EXPECT_EQ(kNumEchoRpcs / 2,
- backends_[i]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service2()->request_count());
- }
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[2]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service2()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- EXPECT_EQ(kNumEcho2Rpcs, backends_[3]->backend_service2()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingPrefixMatchingCaseInsensitive) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kNumEcho1Rpcs = 10;
- const size_t kNumEchoRpcs = 30;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- // First route will not match, since it's case-sensitive.
- // Second route will match with same path.
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/GrPc.TeStInG.EcHoTeSt1SErViCe");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_prefix("/GrPc.TeStInG.EcHoTeSt1SErViCe");
- route2->mutable_match()->mutable_case_sensitive()->set_value(false);
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_wait_for_ready(true));
- CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_wait_for_ready(true));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[2]->backend_service1()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingPathRegexMatching) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kNumEcho1Rpcs = 10;
- const size_t kNumEcho2Rpcs = 20;
- const size_t kNumEchoRpcs = 30;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- // Will match "/grpc.testing.EchoTest1Service/"
- route1->mutable_match()->mutable_safe_regex()->set_regex(".*1.*");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- // Will match "/grpc.testing.EchoTest2Service/"
- route2->mutable_match()->mutable_safe_regex()->set_regex(".*2.*");
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 2);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_wait_for_ready(true));
- CheckRpcSendOk(
- kNumEcho1Rpcs,
- RpcOptions().set_rpc_service(SERVICE_ECHO1).set_wait_for_ready(true));
- CheckRpcSendOk(
- kNumEcho2Rpcs,
- RpcOptions().set_rpc_service(SERVICE_ECHO2).set_wait_for_ready(true));
- // Make sure RPCs all go to the correct backend.
- for (size_t i = 0; i < 2; ++i) {
- EXPECT_EQ(kNumEchoRpcs / 2,
- backends_[i]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service2()->request_count());
- }
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[2]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service2()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- EXPECT_EQ(kNumEcho2Rpcs, backends_[3]->backend_service2()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingWeightedCluster) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kNotUsedClusterName = "not_used_cluster";
- const size_t kNumEchoRpcs = 10; // RPCs that will go to a fixed backend.
- const size_t kWeight75 = 75;
- const size_t kWeight25 = 25;
- const double kErrorTolerance = 0.05;
- const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
- const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
- const size_t kNumEcho1Rpcs =
- ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- auto* weighted_cluster2 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster2->set_name(kNewCluster2Name);
- weighted_cluster2->mutable_weight()->set_value(kWeight25);
- // Cluster with weight 0 will not be used.
- auto* weighted_cluster3 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster3->set_name(kNotUsedClusterName);
- weighted_cluster3->mutable_weight()->set_value(0);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75 + kWeight25);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 1);
- WaitForAllBackends(1, 3, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- const int weight_75_request_count =
- backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- const int weight_25_request_count =
- backends_[2]->backend_service1()->request_count();
- gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
- weight_75_request_count, weight_25_request_count);
- EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs,
- ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs,
- ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
- }
- TEST_P(LdsRdsTest, RouteActionWeightedTargetDefaultRoute) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const size_t kWeight75 = 75;
- const size_t kWeight25 = 25;
- const double kErrorTolerance = 0.05;
- const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
- const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
- const size_t kNumEchoRpcs =
- ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Populating Route Configurations for LDS.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- auto* weighted_cluster2 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster2->set_name(kNewCluster2Name);
- weighted_cluster2->mutable_weight()->set_value(kWeight25);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75 + kWeight25);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(1, 3);
- CheckRpcSendOk(kNumEchoRpcs);
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
- const int weight_75_request_count =
- backends_[1]->backend_service()->request_count();
- const int weight_25_request_count =
- backends_[2]->backend_service()->request_count();
- gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
- weight_75_request_count, weight_25_request_count);
- EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEchoRpcs,
- ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEchoRpcs,
- ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
- }
- TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateWeights) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kNewCluster3Name = "new_cluster_3";
- const char* kNewEdsService3Name = "new_eds_service_name_3";
- const size_t kNumEchoRpcs = 10;
- const size_t kWeight75 = 75;
- const size_t kWeight25 = 25;
- const size_t kWeight50 = 50;
- const double kErrorTolerance = 0.05;
- const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
- const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
- const double kWeight50Percent = static_cast<double>(kWeight50) / 100;
- const size_t kNumEcho1Rpcs7525 =
- ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
- const size_t kNumEcho1Rpcs5050 =
- ComputeIdealNumRpcs(kWeight50Percent, kErrorTolerance);
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args3({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args3, kNewEdsService3Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- Cluster new_cluster3 = default_cluster_;
- new_cluster3.set_name(kNewCluster3Name);
- new_cluster3.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService3Name);
- balancer_->ads_service()->SetCdsResource(new_cluster3);
- // Populating Route Configurations.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- auto* weighted_cluster2 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster2->set_name(kNewCluster2Name);
- weighted_cluster2->mutable_weight()->set_value(kWeight25);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75 + kWeight25);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 1);
- WaitForAllBackends(1, 3, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs7525,
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- const int weight_75_request_count =
- backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[1]->backend_service2()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- const int weight_25_request_count =
- backends_[2]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
- weight_75_request_count, weight_25_request_count);
- EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
- // Change Route Configurations: same clusters different weights.
- weighted_cluster1->mutable_weight()->set_value(kWeight50);
- weighted_cluster2->mutable_weight()->set_value(kWeight50);
- // Change default route to a new cluster to help to identify when new
- // polices are seen by the client.
- default_route->mutable_route()->set_cluster(kNewCluster3Name);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- ResetBackendCounters();
- WaitForAllBackends(3, 4);
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs5050,
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- const int weight_50_request_count_1 =
- backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- const int weight_50_request_count_2 =
- backends_[2]->backend_service1()->request_count();
- EXPECT_EQ(kNumEchoRpcs, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- EXPECT_THAT(
- static_cast<double>(weight_50_request_count_1) / kNumEcho1Rpcs5050,
- ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
- EXPECT_THAT(
- static_cast<double>(weight_50_request_count_2) / kNumEcho1Rpcs5050,
- ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
- }
- TEST_P(LdsRdsTest, XdsRoutingWeightedClusterUpdateClusters) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kNewCluster3Name = "new_cluster_3";
- const char* kNewEdsService3Name = "new_eds_service_name_3";
- const size_t kNumEchoRpcs = 10;
- const size_t kWeight75 = 75;
- const size_t kWeight25 = 25;
- const size_t kWeight50 = 50;
- const double kErrorTolerance = 0.05;
- const double kWeight75Percent = static_cast<double>(kWeight75) / 100;
- const double kWeight25Percent = static_cast<double>(kWeight25) / 100;
- const double kWeight50Percent = static_cast<double>(kWeight50) / 100;
- const size_t kNumEcho1Rpcs7525 =
- ComputeIdealNumRpcs(kWeight75Percent, kErrorTolerance);
- const size_t kNumEcho1Rpcs5050 =
- ComputeIdealNumRpcs(kWeight50Percent, kErrorTolerance);
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args3({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args3, kNewEdsService3Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- Cluster new_cluster3 = default_cluster_;
- new_cluster3.set_name(kNewCluster3Name);
- new_cluster3.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService3Name);
- balancer_->ads_service()->SetCdsResource(new_cluster3);
- // Populating Route Configurations.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* weighted_cluster1 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster1->set_name(kNewCluster1Name);
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- auto* weighted_cluster2 =
- route1->mutable_route()->mutable_weighted_clusters()->add_clusters();
- weighted_cluster2->set_name(kDefaultClusterName);
- weighted_cluster2->mutable_weight()->set_value(kWeight25);
- route1->mutable_route()
- ->mutable_weighted_clusters()
- ->mutable_total_weight()
- ->set_value(kWeight75 + kWeight25);
- auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForBackend(0);
- WaitForBackend(1, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs7525,
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- int weight_25_request_count =
- backends_[0]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- int weight_75_request_count =
- backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
- weight_75_request_count, weight_25_request_count);
- EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
- // Change Route Configurations: new set of clusters with different weights.
- weighted_cluster1->mutable_weight()->set_value(kWeight50);
- weighted_cluster2->set_name(kNewCluster2Name);
- weighted_cluster2->mutable_weight()->set_value(kWeight50);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- ResetBackendCounters();
- WaitForBackend(2, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs5050,
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- const int weight_50_request_count_1 =
- backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- const int weight_50_request_count_2 =
- backends_[2]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service1()->request_count());
- EXPECT_THAT(
- static_cast<double>(weight_50_request_count_1) / kNumEcho1Rpcs5050,
- ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
- EXPECT_THAT(
- static_cast<double>(weight_50_request_count_2) / kNumEcho1Rpcs5050,
- ::testing::DoubleNear(kWeight50Percent, kErrorTolerance));
- // Change Route Configurations.
- weighted_cluster1->mutable_weight()->set_value(kWeight75);
- weighted_cluster2->set_name(kNewCluster3Name);
- weighted_cluster2->mutable_weight()->set_value(kWeight25);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- ResetBackendCounters();
- WaitForBackend(3, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs7525,
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- weight_75_request_count = backends_[1]->backend_service1()->request_count();
- EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[2]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[3]->backend_service()->request_count());
- weight_25_request_count = backends_[3]->backend_service1()->request_count();
- gpr_log(GPR_INFO, "target_75 received %d rpcs and target_25 received %d rpcs",
- weight_75_request_count, weight_25_request_count);
- EXPECT_THAT(static_cast<double>(weight_75_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight75Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_25_request_count) / kNumEcho1Rpcs7525,
- ::testing::DoubleNear(kWeight25Percent, kErrorTolerance));
- }
- TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClusters) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- const size_t kNumEchoRpcs = 5;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Send Route Configuration.
- RouteConfiguration new_route_config = default_route_config_;
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(0, 1);
- CheckRpcSendOk(kNumEchoRpcs);
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- // Change Route Configurations: new default cluster.
- auto* default_route =
- new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- default_route->mutable_route()->set_cluster(kNewClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- WaitForAllBackends(1, 2);
- CheckRpcSendOk(kNumEchoRpcs);
- // Make sure RPCs all go to the correct backend.
- EXPECT_EQ(kNumEchoRpcs, backends_[1]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingClusterUpdateClustersWithPickingDelays) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Bring down the current backend: 0, this will delay route picking time,
- // resulting in un-committed RPCs.
- ShutdownBackend(0);
- // Send a RouteConfiguration with a default route that points to
- // backend 0.
- RouteConfiguration new_route_config = default_route_config_;
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // Send exactly one RPC with no deadline and with wait_for_ready=true.
- // This RPC will not complete until after backend 0 is started.
- std::thread sending_rpc([this]() {
- CheckRpcSendOk(1, RpcOptions().set_wait_for_ready(true).set_timeout_ms(0));
- });
- // Send a non-wait_for_ready RPC which should fail, this will tell us
- // that the client has received the update and attempted to connect.
- const Status status = SendRpc(RpcOptions().set_timeout_ms(0));
- EXPECT_FALSE(status.ok());
- // Send a update RouteConfiguration to use backend 1.
- auto* default_route =
- new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- default_route->mutable_route()->set_cluster(kNewClusterName);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // Wait for RPCs to go to the new backend: 1, this ensures that the client
- // has processed the update.
- WaitForBackend(
- 1, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
- true));
- // Bring up the previous backend: 0, this will allow the delayed RPC to
- // finally call on_call_committed upon completion.
- StartBackend(0);
- sending_rpc.join();
- // Make sure RPCs go to the correct backend:
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(1, backends_[1]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRoutingApplyXdsTimeout) {
- const int64_t kTimeoutMillis = 500;
- const int64_t kTimeoutNano = kTimeoutMillis * 1000000;
- const int64_t kTimeoutGrpcTimeoutHeaderMaxSecond = 1;
- const int64_t kTimeoutMaxStreamDurationSecond = 2;
- const int64_t kTimeoutHttpMaxStreamDurationSecond = 3;
- const int64_t kTimeoutApplicationSecond = 4;
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kNewCluster3Name = "new_cluster_3";
- const char* kNewEdsService3Name = "new_eds_service_name_3";
- // Populate new EDS resources.
- EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
- EdsResourceArgs args1({{"locality0", {MakeNonExistantEndpoint()}}});
- EdsResourceArgs args2({{"locality0", {MakeNonExistantEndpoint()}}});
- EdsResourceArgs args3({{"locality0", {MakeNonExistantEndpoint()}}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args3, kNewEdsService3Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- Cluster new_cluster3 = default_cluster_;
- new_cluster3.set_name(kNewCluster3Name);
- new_cluster3.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService3Name);
- balancer_->ads_service()->SetCdsResource(new_cluster3);
- // Construct listener.
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- // Set up HTTP max_stream_duration of 3.5 seconds
- auto* duration =
- http_connection_manager.mutable_common_http_protocol_options()
- ->mutable_max_stream_duration();
- duration->set_seconds(kTimeoutHttpMaxStreamDurationSecond);
- duration->set_nanos(kTimeoutNano);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- // Construct route config.
- RouteConfiguration new_route_config = default_route_config_;
- // route 1: Set max_stream_duration of 2.5 seconds, Set
- // grpc_timeout_header_max of 1.5
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/Echo1");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* max_stream_duration =
- route1->mutable_route()->mutable_max_stream_duration();
- duration = max_stream_duration->mutable_max_stream_duration();
- duration->set_seconds(kTimeoutMaxStreamDurationSecond);
- duration->set_nanos(kTimeoutNano);
- duration = max_stream_duration->mutable_grpc_timeout_header_max();
- duration->set_seconds(kTimeoutGrpcTimeoutHeaderMaxSecond);
- duration->set_nanos(kTimeoutNano);
- // route 2: Set max_stream_duration of 2.5 seconds
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_path("/grpc.testing.EchoTest2Service/Echo2");
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- max_stream_duration = route2->mutable_route()->mutable_max_stream_duration();
- duration = max_stream_duration->mutable_max_stream_duration();
- duration->set_seconds(kTimeoutMaxStreamDurationSecond);
- duration->set_nanos(kTimeoutNano);
- // route 3: No timeout values in route configuration
- auto* route3 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route3->mutable_match()->set_path("/grpc.testing.EchoTestService/Echo");
- route3->mutable_route()->set_cluster(kNewCluster3Name);
- // Set listener and route config.
- SetListenerAndRouteConfiguration(balancer_.get(), std::move(listener),
- new_route_config);
- // Test grpc_timeout_header_max of 1.5 seconds applied
- grpc_core::Timestamp t0 = NowFromCycleCounter();
- grpc_core::Timestamp t1 =
- t0 + grpc_core::Duration::Seconds(kTimeoutGrpcTimeoutHeaderMaxSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- grpc_core::Timestamp t2 =
- t0 + grpc_core::Duration::Seconds(kTimeoutMaxStreamDurationSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_wait_for_ready(true)
- .set_timeout_ms(grpc_core::Duration::Seconds(
- kTimeoutApplicationSecond)
- .millis()))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_THAT(NowFromCycleCounter(), AdjustedClockInRange(t1, t2));
- // Test max_stream_duration of 2.5 seconds applied
- t0 = NowFromCycleCounter();
- t1 = t0 + grpc_core::Duration::Seconds(kTimeoutMaxStreamDurationSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- t2 = t0 + grpc_core::Duration::Seconds(kTimeoutHttpMaxStreamDurationSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions()
- .set_rpc_service(SERVICE_ECHO2)
- .set_rpc_method(METHOD_ECHO2)
- .set_wait_for_ready(true)
- .set_timeout_ms(grpc_core::Duration::Seconds(
- kTimeoutApplicationSecond)
- .millis()))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_THAT(NowFromCycleCounter(), AdjustedClockInRange(t1, t2));
- // Test http_stream_duration of 3.5 seconds applied
- t0 = NowFromCycleCounter();
- t1 = t0 + grpc_core::Duration::Seconds(kTimeoutHttpMaxStreamDurationSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- t2 = t0 + grpc_core::Duration::Seconds(kTimeoutApplicationSecond) +
- grpc_core::Duration::Milliseconds(kTimeoutMillis);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_wait_for_ready(true).set_timeout_ms(
- grpc_core::Duration::Seconds(kTimeoutApplicationSecond).millis()))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_THAT(NowFromCycleCounter(), AdjustedClockInRange(t1, t2));
- }
- TEST_P(LdsRdsTest, XdsRoutingApplyApplicationTimeoutWhenXdsTimeoutExplicit0) {
- const int64_t kTimeoutNano = 500000000;
- const int64_t kTimeoutMaxStreamDurationSecond = 2;
- const int64_t kTimeoutHttpMaxStreamDurationSecond = 3;
- const int64_t kTimeoutApplicationSecond = 4;
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- // Populate new EDS resources.
- EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
- EdsResourceArgs args1({{"locality0", {MakeNonExistantEndpoint()}}});
- EdsResourceArgs args2({{"locality0", {MakeNonExistantEndpoint()}}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Construct listener.
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- // Set up HTTP max_stream_duration of 3.5 seconds
- auto* duration =
- http_connection_manager.mutable_common_http_protocol_options()
- ->mutable_max_stream_duration();
- duration->set_seconds(kTimeoutHttpMaxStreamDurationSecond);
- duration->set_nanos(kTimeoutNano);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- // Construct route config.
- RouteConfiguration new_route_config = default_route_config_;
- // route 1: Set max_stream_duration of 2.5 seconds, Set
- // grpc_timeout_header_max of 0
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_path("/grpc.testing.EchoTest1Service/Echo1");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* max_stream_duration =
- route1->mutable_route()->mutable_max_stream_duration();
- duration = max_stream_duration->mutable_max_stream_duration();
- duration->set_seconds(kTimeoutMaxStreamDurationSecond);
- duration->set_nanos(kTimeoutNano);
- duration = max_stream_duration->mutable_grpc_timeout_header_max();
- duration->set_seconds(0);
- duration->set_nanos(0);
- // route 2: Set max_stream_duration to 0
- auto* route2 = new_route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_path("/grpc.testing.EchoTest2Service/Echo2");
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- max_stream_duration = route2->mutable_route()->mutable_max_stream_duration();
- duration = max_stream_duration->mutable_max_stream_duration();
- duration->set_seconds(0);
- duration->set_nanos(0);
- // Set listener and route config.
- SetListenerAndRouteConfiguration(balancer_.get(), std::move(listener),
- new_route_config);
- // Test application timeout is applied for route 1
- auto t0 = system_clock::now();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_wait_for_ready(true)
- .set_timeout_ms(kTimeoutApplicationSecond * 1000))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- auto ellapsed_nano_seconds =
- std::chrono::duration_cast<std::chrono::nanoseconds>(system_clock::now() -
- t0);
- EXPECT_GT(ellapsed_nano_seconds.count(),
- kTimeoutApplicationSecond * 1000000000);
- // Test application timeout is applied for route 2
- t0 = system_clock::now();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions()
- .set_rpc_service(SERVICE_ECHO2)
- .set_rpc_method(METHOD_ECHO2)
- .set_wait_for_ready(true)
- .set_timeout_ms(kTimeoutApplicationSecond * 1000))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- ellapsed_nano_seconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
- system_clock::now() - t0);
- EXPECT_GT(ellapsed_nano_seconds.count(),
- kTimeoutApplicationSecond * 1000000000);
- }
- TEST_P(LdsRdsTest, XdsRoutingApplyApplicationTimeoutWhenHttpTimeoutExplicit0) {
- const int64_t kTimeoutApplicationSecond = 4;
- // Populate new EDS resources.
- EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- auto listener = default_listener_;
- HttpConnectionManager http_connection_manager;
- listener.mutable_api_listener()->mutable_api_listener()->UnpackTo(
- &http_connection_manager);
- // Set up HTTP max_stream_duration to be explicit 0
- auto* duration =
- http_connection_manager.mutable_common_http_protocol_options()
- ->mutable_max_stream_duration();
- duration->set_seconds(0);
- duration->set_nanos(0);
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- // Set listener and route config.
- SetListenerAndRouteConfiguration(balancer_.get(), std::move(listener),
- default_route_config_);
- // Test application timeout is applied for route 1
- auto t0 = system_clock::now();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_wait_for_ready(true).set_timeout_ms(
- grpc_core::Duration::Seconds(kTimeoutApplicationSecond).millis()))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- auto ellapsed_nano_seconds =
- std::chrono::duration_cast<std::chrono::nanoseconds>(system_clock::now() -
- t0);
- EXPECT_GT(ellapsed_nano_seconds.count(),
- kTimeoutApplicationSecond * 1000000000);
- }
- // Test to ensure application-specified deadline won't be affected when
- // the xDS config does not specify a timeout.
- TEST_P(LdsRdsTest, XdsRoutingWithOnlyApplicationTimeout) {
- const int64_t kTimeoutApplicationSecond = 4;
- // Populate new EDS resources.
- EdsResourceArgs args({{"locality0", {MakeNonExistantEndpoint()}}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- auto t0 = system_clock::now();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_wait_for_ready(true).set_timeout_ms(
- grpc_core::Duration::Seconds(kTimeoutApplicationSecond).millis()))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- auto ellapsed_nano_seconds =
- std::chrono::duration_cast<std::chrono::nanoseconds>(system_clock::now() -
- t0);
- EXPECT_GT(ellapsed_nano_seconds.count(),
- kTimeoutApplicationSecond * 1000000000);
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyNumRetries) {
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on(
- "5xx,cancelled,deadline-exceeded,internal,resource-exhausted,"
- "unavailable");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // Ensure we retried the correct number of times on all supported status.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions().set_server_expected_error(StatusCode::CANCELLED))
- .set_expected_error_code(StatusCode::CANCELLED));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- ResetBackendCounters();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::DEADLINE_EXCEEDED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- ResetBackendCounters();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions().set_server_expected_error(StatusCode::INTERNAL))
- .set_expected_error_code(StatusCode::INTERNAL));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- ResetBackendCounters();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::RESOURCE_EXHAUSTED))
- .set_expected_error_code(StatusCode::RESOURCE_EXHAUSTED));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- ResetBackendCounters();
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions().set_server_expected_error(StatusCode::UNAVAILABLE))
- .set_expected_error_code(StatusCode::UNAVAILABLE));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- ResetBackendCounters();
- // Ensure we don't retry on an unsupported status.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::UNAUTHENTICATED))
- .set_expected_error_code(StatusCode::UNAUTHENTICATED));
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyAtVirtualHostLevel) {
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* retry_policy =
- new_route_config.mutable_virtual_hosts(0)->mutable_retry_policy();
- retry_policy->set_retry_on(
- "cancelled,deadline-exceeded,internal,resource-exhausted,unavailable");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // Ensure we retried the correct number of times on a supported status.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::DEADLINE_EXCEEDED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(kNumRetries + 1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyLongBackOff) {
- // Set num retries to 3, but due to longer back off, we expect only 1 retry
- // will take place.
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on(
- "5xx,cancelled,deadline-exceeded,internal,resource-exhausted,"
- "unavailable");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- auto base_interval =
- retry_policy->mutable_retry_back_off()->mutable_base_interval();
- // Set backoff to 1 second, 1/2 of rpc timeout of 2 second.
- base_interval->set_seconds(1 * grpc_test_slowdown_factor());
- base_interval->set_nanos(0);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // No need to set max interval and just let it be the default of 10x of base.
- // We expect 1 retry before the RPC times out with DEADLINE_EXCEEDED.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions().set_timeout_ms(2500).set_server_expected_error(
- StatusCode::CANCELLED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(1 + 1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyMaxBackOff) {
- // Set num retries to 3, but due to longer back off, we expect only 2 retry
- // will take place, while the 2nd one will obey the max backoff.
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on(
- "5xx,cancelled,deadline-exceeded,internal,resource-exhausted,"
- "unavailable");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- auto base_interval =
- retry_policy->mutable_retry_back_off()->mutable_base_interval();
- // Set backoff to 1 second.
- base_interval->set_seconds(1 * grpc_test_slowdown_factor());
- base_interval->set_nanos(0);
- auto max_interval =
- retry_policy->mutable_retry_back_off()->mutable_max_interval();
- // Set max interval to be the same as base, so 2 retries will take 2 seconds
- // and both retries will take place before the 2.5 seconds rpc timeout.
- // Tested to ensure if max is not set, this test will be the same as
- // XdsRetryPolicyLongBackOff and we will only see 1 retry in that case.
- max_interval->set_seconds(1 * grpc_test_slowdown_factor());
- max_interval->set_nanos(0);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // We expect 2 retry before the RPC times out with DEADLINE_EXCEEDED.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(
- RpcOptions().set_timeout_ms(2500).set_server_expected_error(
- StatusCode::CANCELLED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(2 + 1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyUnsupportedStatusCode) {
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on("5xx");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // We expect no retry.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::DEADLINE_EXCEEDED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest,
- XdsRetryPolicyUnsupportedStatusCodeWithVirtualHostLevelRetry) {
- const size_t kNumRetries = 3;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy with no supported retry_on
- // statuses.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on("5xx");
- retry_policy->mutable_num_retries()->set_value(kNumRetries);
- // Construct a virtual host level retry policy with supported statuses.
- auto* virtual_host_retry_policy =
- new_route_config.mutable_virtual_hosts(0)->mutable_retry_policy();
- virtual_host_retry_policy->set_retry_on(
- "cancelled,deadline-exceeded,internal,resource-exhausted,unavailable");
- virtual_host_retry_policy->mutable_num_retries()->set_value(kNumRetries);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- // We expect no retry.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_server_expected_error(
- StatusCode::DEADLINE_EXCEEDED))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyInvalidNumRetriesZero) {
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on("deadline-exceeded");
- // Setting num_retries to zero is not valid.
- retry_policy->mutable_num_retries()->set_value(0);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "RouteAction RetryPolicy num_retries set to invalid value 0."));
- }
- TEST_P(LdsRdsTest, XdsRetryPolicyRetryBackOffMissingBaseInterval) {
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct route config to set retry policy.
- RouteConfiguration new_route_config = default_route_config_;
- auto* route1 = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* retry_policy = route1->mutable_route()->mutable_retry_policy();
- retry_policy->set_retry_on("deadline-exceeded");
- retry_policy->mutable_num_retries()->set_value(1);
- // RetryBackoff is there but base interval is missing.
- auto max_interval =
- retry_policy->mutable_retry_back_off()->mutable_max_interval();
- max_interval->set_seconds(0);
- max_interval->set_nanos(250000000);
- SetRouteConfiguration(balancer_.get(), new_route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "RouteAction RetryPolicy RetryBackoff missing base interval."));
- }
- TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- const size_t kNumEcho1Rpcs = 100;
- const size_t kNumEchoRpcs = 5;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("header1");
- header_matcher1->set_exact_match("POST,PUT,GET");
- auto* header_matcher2 = route1->mutable_match()->add_headers();
- header_matcher2->set_name("header2");
- header_matcher2->mutable_safe_regex_match()->set_regex("[a-z]*");
- auto* header_matcher3 = route1->mutable_match()->add_headers();
- header_matcher3->set_name("header3");
- header_matcher3->mutable_range_match()->set_start(1);
- header_matcher3->mutable_range_match()->set_end(1000);
- auto* header_matcher4 = route1->mutable_match()->add_headers();
- header_matcher4->set_name("header4");
- header_matcher4->set_present_match(false);
- auto* header_matcher5 = route1->mutable_match()->add_headers();
- header_matcher5->set_name("header5");
- header_matcher5->set_present_match(true);
- auto* header_matcher6 = route1->mutable_match()->add_headers();
- header_matcher6->set_name("header6");
- header_matcher6->set_prefix_match("/grpc");
- auto* header_matcher7 = route1->mutable_match()->add_headers();
- header_matcher7->set_name("header7");
- header_matcher7->set_suffix_match(".cc");
- header_matcher7->set_invert_match(true);
- route1->mutable_route()->set_cluster(kNewClusterName);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"header1", "POST"},
- {"header2", "blah"},
- {"header3", "1"},
- {"header5", "anything"},
- {"header6", "/grpc.testing.EchoTest1Service/"},
- {"header1", "PUT"},
- {"header7", "grpc.java"},
- {"header1", "GET"},
- };
- const auto header_match_rpc_options = RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_metadata(std::move(metadata));
- // Make sure all backends are up.
- WaitForBackend(0);
- WaitForBackend(1, WaitForBackendOptions(), header_match_rpc_options);
- // Send RPCs.
- CheckRpcSendOk(kNumEchoRpcs);
- CheckRpcSendOk(kNumEcho1Rpcs, header_match_rpc_options);
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service2()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[1]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service2()->request_count());
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderContentType) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- const size_t kNumEchoRpcs = 100;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("content-type");
- header_matcher1->set_exact_match("notapplication/grpc");
- route1->mutable_route()->set_cluster(kNewClusterName);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- auto* header_matcher2 = default_route->mutable_match()->add_headers();
- header_matcher2->set_name("content-type");
- header_matcher2->set_exact_match("application/grpc");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Make sure the backend is up.
- WaitForAllBackends(0, 1);
- // Send RPCs.
- CheckRpcSendOk(kNumEchoRpcs);
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const size_t kNumEchoRpcs = 100;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("grpc-foo-bin");
- header_matcher1->set_present_match(true);
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Send headers which will mismatch each route
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"grpc-foo-bin", "grpc-foo-bin"},
- };
- WaitForAllBackends(0, 1);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata));
- // Verify that only the default backend got RPCs since all previous routes
- // were mismatched.
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- const double kErrorTolerance = 0.05;
- const size_t kRouteMatchNumerator = 25;
- const double kRouteMatchPercent =
- static_cast<double>(kRouteMatchNumerator) / 100;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kRouteMatchPercent, kErrorTolerance);
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()
- ->mutable_runtime_fraction()
- ->mutable_default_value()
- ->set_numerator(kRouteMatchNumerator);
- route1->mutable_route()->set_cluster(kNewClusterName);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- WaitForAllBackends(0, 2);
- CheckRpcSendOk(kNumRpcs);
- const int default_backend_count =
- backends_[0]->backend_service()->request_count();
- const int matched_backend_count =
- backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(default_backend_count) / kNumRpcs,
- ::testing::DoubleNear(1 - kRouteMatchPercent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(matched_backend_count) / kNumRpcs,
- ::testing::DoubleNear(kRouteMatchPercent, kErrorTolerance));
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingUnmatchCases) {
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kNewCluster3Name = "new_cluster_3";
- const char* kNewEdsService3Name = "new_eds_service_name_3";
- const size_t kNumEcho1Rpcs = 100;
- const size_t kNumEchoRpcs = 5;
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- EdsResourceArgs args3({
- {"locality0", CreateEndpointsForBackends(3, 4)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args3, kNewEdsService3Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- Cluster new_cluster3 = default_cluster_;
- new_cluster3.set_name(kNewCluster3Name);
- new_cluster3.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService3Name);
- balancer_->ads_service()->SetCdsResource(new_cluster3);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher1 = route1->mutable_match()->add_headers();
- header_matcher1->set_name("header1");
- header_matcher1->set_exact_match("POST");
- route1->mutable_route()->set_cluster(kNewCluster1Name);
- auto route2 = route_config.mutable_virtual_hosts(0)->add_routes();
- route2->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher2 = route2->mutable_match()->add_headers();
- header_matcher2->set_name("header2");
- header_matcher2->mutable_range_match()->set_start(1);
- header_matcher2->mutable_range_match()->set_end(1000);
- route2->mutable_route()->set_cluster(kNewCluster2Name);
- auto route3 = route_config.mutable_virtual_hosts(0)->add_routes();
- route3->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- auto* header_matcher3 = route3->mutable_match()->add_headers();
- header_matcher3->set_name("header3");
- header_matcher3->mutable_safe_regex_match()->set_regex("[a-z]*");
- route3->mutable_route()->set_cluster(kNewCluster3Name);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Send headers which will mismatch each route
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"header1", "POST"},
- {"header2", "1000"},
- {"header3", "123"},
- {"header1", "GET"},
- };
- WaitForAllBackends(0, 1);
- CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata));
- CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions()
- .set_rpc_service(SERVICE_ECHO1)
- .set_rpc_method(METHOD_ECHO1)
- .set_metadata(metadata));
- // Verify that only the default backend got RPCs since all previous routes
- // were mismatched.
- for (size_t i = 1; i < 4; ++i) {
- EXPECT_EQ(0, backends_[i]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[i]->backend_service2()->request_count());
- }
- EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(kNumEcho1Rpcs, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service2()->request_count());
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(LdsRdsTest, XdsRoutingChangeRoutesWithoutChangingClusters) {
- const char* kNewClusterName = "new_cluster";
- const char* kNewEdsServiceName = "new_eds_service_name";
- // Populate new EDS resources.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName));
- // Populate new CDS resources.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Populating Route Configurations for LDS.
- RouteConfiguration route_config = default_route_config_;
- auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
- route1->mutable_route()->set_cluster(kNewClusterName);
- auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
- default_route->mutable_match()->set_prefix("");
- default_route->mutable_route()->set_cluster(kDefaultClusterName);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Make sure all backends are up and that requests for each RPC
- // service go to the right backends.
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
- WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
- RpcOptions().set_rpc_service(SERVICE_ECHO2));
- // Requests for services Echo and Echo2 should have gone to backend 0.
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(1, backends_[0]->backend_service2()->request_count());
- // Requests for service Echo1 should have gone to backend 1.
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- EXPECT_EQ(1, backends_[1]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service2()->request_count());
- // Now send an update that changes the first route to match a
- // different RPC service, and wait for the client to make the change.
- route1->mutable_match()->set_prefix("/grpc.testing.EchoTest2Service/");
- SetRouteConfiguration(balancer_.get(), route_config);
- WaitForBackend(1, WaitForBackendOptions(),
- RpcOptions().set_rpc_service(SERVICE_ECHO2));
- // Now repeat the earlier test, making sure all traffic goes to the
- // right place.
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
- RpcOptions().set_rpc_service(SERVICE_ECHO1));
- WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false),
- RpcOptions().set_rpc_service(SERVICE_ECHO2));
- // Requests for services Echo and Echo1 should have gone to backend 0.
- EXPECT_EQ(1, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(1, backends_[0]->backend_service1()->request_count());
- EXPECT_EQ(0, backends_[0]->backend_service2()->request_count());
- // Requests for service Echo2 should have gone to backend 1.
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service1()->request_count());
- EXPECT_EQ(1, backends_[1]->backend_service2()->request_count());
- }
- // Test that we NACK unknown filter types in VirtualHost.
- TEST_P(LdsRdsTest, RejectsUnknownHttpFilterTypeInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(Listener());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("no filter registered for config type "
- "envoy.config.listener.v3.Listener"));
- }
- // Test that we ignore optional unknown filter types in VirtualHost.
- TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.mutable_config()->PackFrom(Listener());
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK filters without configs in VirtualHost.
- TEST_P(LdsRdsTest, RejectsHttpFilterWithoutConfigInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"];
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we NACK filters without configs in FilterConfig in VirtualHost.
- TEST_P(LdsRdsTest, RejectsHttpFilterWithoutConfigInFilterConfigInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- ::envoy::config::route::v3::FilterConfig());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we ignore optional filters without configs in VirtualHost.
- TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK unparseable filter types in VirtualHost.
- TEST_P(LdsRdsTest, RejectsUnparseableHttpFilterTypeInVirtualHost) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config =
- route_config.mutable_virtual_hosts(0)->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("router filter does not support config override"));
- }
- // Test that we NACK unknown filter types in Route.
- TEST_P(LdsRdsTest, RejectsUnknownHttpFilterTypeInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(Listener());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("no filter registered for config type "
- "envoy.config.listener.v3.Listener"));
- }
- // Test that we ignore optional unknown filter types in Route.
- TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.mutable_config()->PackFrom(Listener());
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK filters without configs in Route.
- TEST_P(LdsRdsTest, RejectsHttpFilterWithoutConfigInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"];
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we NACK filters without configs in FilterConfig in Route.
- TEST_P(LdsRdsTest, RejectsHttpFilterWithoutConfigInFilterConfigInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- ::envoy::config::route::v3::FilterConfig());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we ignore optional filters without configs in Route.
- TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK unparseable filter types in Route.
- TEST_P(LdsRdsTest, RejectsUnparseableHttpFilterTypeInRoute) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* per_filter_config = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("router filter does not support config override"));
- }
- // Test that we NACK unknown filter types in ClusterWeight.
- TEST_P(LdsRdsTest, RejectsUnknownHttpFilterTypeInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(Listener());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("no filter registered for config type "
- "envoy.config.listener.v3.Listener"));
- }
- // Test that we ignore optional unknown filter types in ClusterWeight.
- TEST_P(LdsRdsTest, IgnoresOptionalUnknownHttpFilterTypeInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.mutable_config()->PackFrom(Listener());
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK filters without configs in ClusterWeight.
- TEST_P(LdsRdsTest, RejectsHttpFilterWithoutConfigInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"];
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we NACK filters without configs in FilterConfig in ClusterWeight.
- TEST_P(LdsRdsTest,
- RejectsHttpFilterWithoutConfigInFilterConfigInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- ::envoy::config::route::v3::FilterConfig());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "no filter config specified for filter name unknown"));
- }
- // Test that we ignore optional filters without configs in ClusterWeight.
- TEST_P(LdsRdsTest, IgnoresOptionalHttpFilterWithoutConfigInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- ::envoy::config::route::v3::FilterConfig filter_config;
- filter_config.set_is_optional(true);
- (*per_filter_config)["unknown"].PackFrom(filter_config);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = RouteConfigurationResponseState(balancer_.get());
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Test that we NACK unparseable filter types in ClusterWeight.
- TEST_P(LdsRdsTest, RejectsUnparseableHttpFilterTypeInClusterWeight) {
- if (GetParam().use_v2()) return; // Filters supported in v3 only.
- RouteConfiguration route_config = default_route_config_;
- auto* cluster_weight = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->mutable_weighted_clusters()
- ->add_clusters();
- cluster_weight->set_name(kDefaultClusterName);
- cluster_weight->mutable_weight()->set_value(100);
- auto* per_filter_config = cluster_weight->mutable_typed_per_filter_config();
- (*per_filter_config)["unknown"].PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- route_config);
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("router filter does not support config override"));
- }
- using CdsTest = BasicTest;
- // Tests that CDS client should send an ACK upon correct CDS response.
- TEST_P(CdsTest, Vanilla) {
- (void)SendRpc();
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- TEST_P(CdsTest, LogicalDNSClusterType) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- auto* address = cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address();
- address->set_address(kServerName);
- address->set_port_value(443);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Set Logical DNS result
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_core::Resolver::Result result;
- result.addresses = CreateAddressListFromPortList(GetBackendPorts(1, 2));
- logical_dns_cluster_resolver_response_generator_->SetResponse(
- std::move(result));
- }
- // Wait for traffic to go to backend 1.
- WaitForBackend(1);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeMissingLoadAssignment) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "load_assignment not present for LOGICAL_DNS cluster"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeMissingLocalities) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("load_assignment for LOGICAL_DNS cluster must have "
- "exactly one locality, found 0"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeMultipleLocalities) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- auto* load_assignment = cluster.mutable_load_assignment();
- load_assignment->add_endpoints();
- load_assignment->add_endpoints();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("load_assignment for LOGICAL_DNS cluster must have "
- "exactly one locality, found 2"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeMissingEndpoints) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()->add_endpoints();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "locality for LOGICAL_DNS cluster must have exactly one "
- "endpoint, found 0"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeMultipleEndpoints) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- auto* locality = cluster.mutable_load_assignment()->add_endpoints();
- locality->add_lb_endpoints();
- locality->add_lb_endpoints();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "locality for LOGICAL_DNS cluster must have exactly one "
- "endpoint, found 2"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeEmptyEndpoint) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()->add_endpoints()->add_lb_endpoints();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("LbEndpoint endpoint field not set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeEndpointMissingAddress) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Endpoint address field not set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeAddressMissingSocketAddress) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Address socket_address field not set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeSocketAddressHasResolverName) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address()
- ->set_resolver_name("foo");
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("LOGICAL_DNS clusters must NOT have a "
- "custom resolver name set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeSocketAddressMissingAddress) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("SocketAddress address field not set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, LogicalDNSClusterTypeSocketAddressMissingPort) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- // Create Logical DNS Cluster
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address()
- ->set_address(kServerName);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("SocketAddress port_value field not set"));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, AggregateClusterType) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- // Populate new EDS resources.
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kNewCluster1Name);
- cluster_config.add_clusters(kNewCluster2Name);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Wait for traffic to go to backend 1.
- WaitForBackend(1);
- // Shutdown backend 1 and wait for all traffic to go to backend 2.
- ShutdownBackend(1);
- WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- // Bring backend 1 back and ensure all traffic go back to it.
- StartBackend(1);
- WaitForBackend(1);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, AggregateClusterFallBackFromRingHashAtStartup) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- // Populate new EDS resources.
- EdsResourceArgs args1({
- {"locality0", {MakeNonExistantEndpoint(), MakeNonExistantEndpoint()}},
- });
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kNewCluster1Name);
- cluster_config.add_clusters(kNewCluster2Name);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Set up route with channel id hashing
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- // Verifying that we are using ring hash as only 1 endpoint is receiving all
- // the traffic.
- CheckRpcSendOk(100);
- bool found = false;
- for (size_t i = 0; i < backends_.size(); ++i) {
- if (backends_[i]->backend_service()->request_count() > 0) {
- EXPECT_EQ(backends_[i]->backend_service()->request_count(), 100)
- << "backend " << i;
- EXPECT_FALSE(found) << "backend " << i;
- found = true;
- }
- }
- EXPECT_TRUE(found);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, AggregateClusterEdsToLogicalDns) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kLogicalDNSClusterName = "logical_dns_cluster";
- // Populate new EDS resources.
- EdsResourceArgs args1({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- // Create Logical DNS Cluster
- auto logical_dns_cluster = default_cluster_;
- logical_dns_cluster.set_name(kLogicalDNSClusterName);
- logical_dns_cluster.set_type(Cluster::LOGICAL_DNS);
- auto* address = logical_dns_cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address();
- address->set_address(kServerName);
- address->set_port_value(443);
- balancer_->ads_service()->SetCdsResource(logical_dns_cluster);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kNewCluster1Name);
- cluster_config.add_clusters(kLogicalDNSClusterName);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Set Logical DNS result
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_core::Resolver::Result result;
- result.addresses = CreateAddressListFromPortList(GetBackendPorts(2, 3));
- logical_dns_cluster_resolver_response_generator_->SetResponse(
- std::move(result));
- }
- // Wait for traffic to go to backend 1.
- WaitForBackend(1);
- // Shutdown backend 1 and wait for all traffic to go to backend 2.
- ShutdownBackend(1);
- WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- // Bring backend 1 back and ensure all traffic go back to it.
- StartBackend(1);
- WaitForBackend(1);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, AggregateClusterLogicalDnsToEds) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewCluster2Name = "new_cluster_2";
- const char* kNewEdsService2Name = "new_eds_service_name_2";
- const char* kLogicalDNSClusterName = "logical_dns_cluster";
- // Populate new EDS resources.
- EdsResourceArgs args2({
- {"locality0", CreateEndpointsForBackends(2, 3)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsService2Name));
- // Populate new CDS resources.
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewCluster2Name);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService2Name);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Create Logical DNS Cluster
- auto logical_dns_cluster = default_cluster_;
- logical_dns_cluster.set_name(kLogicalDNSClusterName);
- logical_dns_cluster.set_type(Cluster::LOGICAL_DNS);
- auto* address = logical_dns_cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address();
- address->set_address(kServerName);
- address->set_port_value(443);
- balancer_->ads_service()->SetCdsResource(logical_dns_cluster);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kLogicalDNSClusterName);
- cluster_config.add_clusters(kNewCluster2Name);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Set Logical DNS result
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_core::Resolver::Result result;
- result.addresses = CreateAddressListFromPortList(GetBackendPorts(1, 2));
- logical_dns_cluster_resolver_response_generator_->SetResponse(
- std::move(result));
- }
- // Wait for traffic to go to backend 1.
- WaitForBackend(1);
- // Shutdown backend 1 and wait for all traffic to go to backend 2.
- ShutdownBackend(1);
- WaitForBackend(2, WaitForBackendOptions().set_allow_failures(true));
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- // Bring backend 1 back and ensure all traffic go back to it.
- StartBackend(1);
- WaitForBackend(1);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- // This test covers a bug seen in the wild where the
- // xds_cluster_resolver policy's code to reuse child policy names did
- // not correctly handle the case where the LOGICAL_DNS priority failed,
- // thus returning a priority with no localities. This caused the child
- // name to be reused incorrectly, which triggered an assertion failure
- // in the xds_cluster_impl policy caused by changing its cluster name.
- TEST_P(CdsTest, AggregateClusterReconfigEdsWhileLogicalDnsChildFails) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewCluster1Name = "new_cluster_1";
- const char* kNewEdsService1Name = "new_eds_service_name_1";
- const char* kLogicalDNSClusterName = "logical_dns_cluster";
- // Populate EDS resource with all unreachable endpoints.
- // - Priority 0: locality0
- // - Priority 1: locality1, locality2
- EdsResourceArgs args1({
- {"locality0", {MakeNonExistantEndpoint()}, kDefaultLocalityWeight, 0},
- {"locality1", {MakeNonExistantEndpoint()}, kDefaultLocalityWeight, 1},
- {"locality2", {MakeNonExistantEndpoint()}, kDefaultLocalityWeight, 1},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- // Populate new CDS resources.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewCluster1Name);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsService1Name);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- // Create Logical DNS Cluster
- auto logical_dns_cluster = default_cluster_;
- logical_dns_cluster.set_name(kLogicalDNSClusterName);
- logical_dns_cluster.set_type(Cluster::LOGICAL_DNS);
- auto* address = logical_dns_cluster.mutable_load_assignment()
- ->add_endpoints()
- ->add_lb_endpoints()
- ->mutable_endpoint()
- ->mutable_address()
- ->mutable_socket_address();
- address->set_address(kServerName);
- address->set_port_value(443);
- balancer_->ads_service()->SetCdsResource(logical_dns_cluster);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kNewCluster1Name);
- cluster_config.add_clusters(kLogicalDNSClusterName);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Set Logical DNS result
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_core::Resolver::Result result;
- result.addresses = absl::UnavailableError("injected error");
- logical_dns_cluster_resolver_response_generator_->SetResponse(
- std::move(result));
- }
- // When an RPC fails, we know the channel has seen the update.
- CheckRpcSendFailure();
- // Send an EDS update that moves locality1 to priority 0.
- args1 = EdsResourceArgs({
- {"locality1", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality2", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 1},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsService1Name));
- WaitForBackend(0, WaitForBackendOptions().set_allow_failures(true));
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- TEST_P(CdsTest, AggregateClusterMultipleClustersWithSameLocalities) {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER",
- "true");
- const char* kNewClusterName1 = "new_cluster_1";
- const char* kNewEdsServiceName1 = "new_eds_service_name_1";
- const char* kNewClusterName2 = "new_cluster_2";
- const char* kNewEdsServiceName2 = "new_eds_service_name_2";
- // Populate EDS resource for cluster 1 with unreachable endpoint.
- EdsResourceArgs args1({{"locality0", {MakeNonExistantEndpoint()}}});
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName1));
- // Populate CDS resource for cluster 1.
- Cluster new_cluster1 = default_cluster_;
- new_cluster1.set_name(kNewClusterName1);
- new_cluster1.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName1);
- balancer_->ads_service()->SetCdsResource(new_cluster1);
- // Populate EDS resource for cluster 2.
- args1 = EdsResourceArgs({{"locality1", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName2));
- // Populate CDS resource for cluster 2.
- Cluster new_cluster2 = default_cluster_;
- new_cluster2.set_name(kNewClusterName2);
- new_cluster2.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName2);
- balancer_->ads_service()->SetCdsResource(new_cluster2);
- // Create Aggregate Cluster
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters(kNewClusterName1);
- cluster_config.add_clusters(kNewClusterName2);
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Wait for channel to get the resources and get connected.
- WaitForBackend(0);
- // Send an EDS update for cluster 1 that reuses the locality name from
- // cluster 1 and points traffic to backend 1.
- args1 = EdsResourceArgs({{"locality1", CreateEndpointsForBackends(1, 2)}});
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args1, kNewEdsServiceName1));
- WaitForBackend(1);
- gpr_unsetenv(
- "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER");
- }
- // Test that CDS client should send a NACK if cluster type is Logical DNS but
- // the feature is not yet supported.
- TEST_P(CdsTest, LogicalDNSClusterTypeDisabled) {
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::LOGICAL_DNS);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("DiscoveryType is not valid."));
- }
- // Test that CDS client should send a NACK if cluster type is AGGREGATE but
- // the feature is not yet supported.
- TEST_P(CdsTest, AggregateClusterTypeDisabled) {
- auto cluster = default_cluster_;
- CustomClusterType* custom_cluster = cluster.mutable_cluster_type();
- custom_cluster->set_name("envoy.clusters.aggregate");
- ClusterConfig cluster_config;
- cluster_config.add_clusters("cluster1");
- cluster_config.add_clusters("cluster2");
- custom_cluster->mutable_typed_config()->PackFrom(cluster_config);
- cluster.set_type(Cluster::LOGICAL_DNS);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("DiscoveryType is not valid."));
- }
- // Tests that CDS client should send a NACK if the cluster type in CDS
- // response is unsupported.
- TEST_P(CdsTest, UnsupportedClusterType) {
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::STATIC);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("DiscoveryType is not valid."));
- }
- // Tests that the NACK for multiple bad resources includes both errors.
- TEST_P(CdsTest, MultipleBadResources) {
- constexpr char kClusterName2[] = "cluster_name_2";
- constexpr char kClusterName3[] = "cluster_name_3";
- // Add cluster with unsupported type.
- auto cluster = default_cluster_;
- cluster.set_name(kClusterName2);
- cluster.set_type(Cluster::STATIC);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Add second cluster with the same error.
- cluster.set_name(kClusterName3);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Change RouteConfig to point to all clusters.
- RouteConfiguration route_config = default_route_config_;
- route_config.mutable_virtual_hosts(0)->clear_routes();
- // First route: default cluster, selected based on header.
- auto* route = route_config.mutable_virtual_hosts(0)->add_routes();
- route->mutable_match()->set_prefix("");
- auto* header_matcher = route->mutable_match()->add_headers();
- header_matcher->set_name("cluster");
- header_matcher->set_exact_match(kDefaultClusterName);
- route->mutable_route()->set_cluster(kDefaultClusterName);
- // Second route: cluster 2, selected based on header.
- route = route_config.mutable_virtual_hosts(0)->add_routes();
- route->mutable_match()->set_prefix("");
- header_matcher = route->mutable_match()->add_headers();
- header_matcher->set_name("cluster");
- header_matcher->set_exact_match(kClusterName2);
- route->mutable_route()->set_cluster(kClusterName2);
- // Third route: cluster 3, used by default.
- route = route_config.mutable_virtual_hosts(0)->add_routes();
- route->mutable_match()->set_prefix("");
- route->mutable_route()->set_cluster(kClusterName3);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Add EDS resource.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send RPC.
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(kClusterName2,
- ": validation error.*"
- "DiscoveryType is not valid.*",
- kClusterName3,
- ": validation error.*"
- "DiscoveryType is not valid")));
- // RPCs for default cluster should succeed.
- std::vector<std::pair<std::string, std::string>> metadata_default_cluster = {
- {"cluster", kDefaultClusterName},
- };
- CheckRpcSendOk(
- 1, RpcOptions().set_metadata(std::move(metadata_default_cluster)));
- // RPCs for cluster 2 should fail.
- std::vector<std::pair<std::string, std::string>> metadata_cluster_2 = {
- {"cluster", kClusterName2},
- };
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_rpc_options(
- RpcOptions().set_metadata(std::move(metadata_cluster_2))));
- }
- // Tests that we don't trigger does-not-exist callbacks for a resource
- // that was previously valid but is updated to be invalid.
- TEST_P(CdsTest, InvalidClusterStillExistsIfPreviouslyCached) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Check that everything works.
- CheckRpcSendOk();
- // Now send an update changing the Cluster to be invalid.
- auto cluster = default_cluster_;
- cluster.set_type(Cluster::STATIC);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack(StatusCode::OK);
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::ContainsRegex(absl::StrCat(
- kDefaultClusterName,
- ": validation error.*DiscoveryType is not valid")));
- }
- // Tests that CDS client should send a NACK if the eds_config in CDS response
- // is other than ADS or SELF.
- TEST_P(CdsTest, EdsConfigSourceDoesNotSpecifyAdsOrSelf) {
- auto cluster = default_cluster_;
- cluster.mutable_eds_cluster_config()->mutable_eds_config()->set_path(
- "/foo/bar");
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("EDS ConfigSource is not ADS or SELF."));
- }
- // Tests that CDS client accepts an eds_config of type ADS.
- TEST_P(CdsTest, AcceptsEdsConfigSourceOfTypeAds) {
- auto cluster = default_cluster_;
- cluster.mutable_eds_cluster_config()->mutable_eds_config()->mutable_ads();
- balancer_->ads_service()->SetCdsResource(cluster);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- auto response_state = balancer_->ads_service()->cds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Tests that CDS client should send a NACK if the lb_policy in CDS response
- // is other than ROUND_ROBIN.
- TEST_P(CdsTest, WrongLbPolicy) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::LEAST_REQUEST);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("LB policy is not supported."));
- }
- // Tests that CDS client should send a NACK if the lrs_server in CDS response
- // is other than SELF.
- TEST_P(CdsTest, WrongLrsServer) {
- auto cluster = default_cluster_;
- cluster.mutable_lrs_server()->mutable_ads();
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("LRS ConfigSource is not self."));
- }
- // Tests that ring hash policy that hashes using channel id ensures all RPCs
- // to go 1 particular backend.
- TEST_P(CdsTest, RingHashChannelIdHashing) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk(100);
- bool found = false;
- for (size_t i = 0; i < backends_.size(); ++i) {
- if (backends_[i]->backend_service()->request_count() > 0) {
- EXPECT_EQ(backends_[i]->backend_service()->request_count(), 100)
- << "backend " << i;
- EXPECT_FALSE(found) << "backend " << i;
- found = true;
- }
- }
- EXPECT_TRUE(found);
- }
- // Tests that ring hash policy that hashes using a header value can spread
- // RPCs across all the backends.
- TEST_P(CdsTest, RingHashHeaderHashing) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Note each type of RPC will contains a header value that will always be
- // hashed to a specific backend as the header value matches the value used
- // to create the entry in the ring.
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- std::vector<std::pair<std::string, std::string>> metadata1 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(1)}};
- std::vector<std::pair<std::string, std::string>> metadata2 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(2)}};
- std::vector<std::pair<std::string, std::string>> metadata3 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(3)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- const auto rpc_options1 = RpcOptions().set_metadata(std::move(metadata1));
- const auto rpc_options2 = RpcOptions().set_metadata(std::move(metadata2));
- const auto rpc_options3 = RpcOptions().set_metadata(std::move(metadata3));
- WaitForBackend(0, WaitForBackendOptions(), rpc_options);
- WaitForBackend(1, WaitForBackendOptions(), rpc_options1);
- WaitForBackend(2, WaitForBackendOptions(), rpc_options2);
- WaitForBackend(3, WaitForBackendOptions(), rpc_options3);
- CheckRpcSendOk(100, rpc_options);
- CheckRpcSendOk(100, rpc_options1);
- CheckRpcSendOk(100, rpc_options2);
- CheckRpcSendOk(100, rpc_options3);
- for (size_t i = 0; i < backends_.size(); ++i) {
- EXPECT_EQ(100, backends_[i]->backend_service()->request_count());
- }
- }
- // Tests that ring hash policy that hashes using a header value and regex
- // rewrite to aggregate RPCs to 1 backend.
- TEST_P(CdsTest, RingHashHeaderHashingWithRegexRewrite) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- hash_policy->mutable_header()
- ->mutable_regex_rewrite()
- ->mutable_pattern()
- ->set_regex("[0-9]+");
- hash_policy->mutable_header()->mutable_regex_rewrite()->set_substitution(
- "foo");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- std::vector<std::pair<std::string, std::string>> metadata1 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(1)}};
- std::vector<std::pair<std::string, std::string>> metadata2 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(2)}};
- std::vector<std::pair<std::string, std::string>> metadata3 = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(3)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- const auto rpc_options1 = RpcOptions().set_metadata(std::move(metadata1));
- const auto rpc_options2 = RpcOptions().set_metadata(std::move(metadata2));
- const auto rpc_options3 = RpcOptions().set_metadata(std::move(metadata3));
- CheckRpcSendOk(100, rpc_options);
- CheckRpcSendOk(100, rpc_options1);
- CheckRpcSendOk(100, rpc_options2);
- CheckRpcSendOk(100, rpc_options3);
- bool found = false;
- for (size_t i = 0; i < backends_.size(); ++i) {
- if (backends_[i]->backend_service()->request_count() > 0) {
- EXPECT_EQ(backends_[i]->backend_service()->request_count(), 400)
- << "backend " << i;
- EXPECT_FALSE(found) << "backend " << i;
- found = true;
- }
- }
- EXPECT_TRUE(found);
- }
- // Tests that ring hash policy that hashes using a random value.
- TEST_P(CdsTest, RingHashNoHashPolicy) {
- const double kDistribution50Percent = 0.5;
- const double kErrorTolerance = 0.05;
- const uint32_t kRpcTimeoutMs = 10000;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kDistribution50Percent, kErrorTolerance);
- auto cluster = default_cluster_;
- // Increasing min ring size for random distribution.
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 100000);
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 2)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // TODO(donnadionne): remove extended timeout after ring creation
- // optimization.
- WaitForAllBackends(0, 2, WaitForBackendOptions(),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- CheckRpcSendOk(kNumRpcs);
- const int request_count_1 = backends_[0]->backend_service()->request_count();
- const int request_count_2 = backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(request_count_1) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- }
- // Test that ring hash policy evaluation will continue past the terminal
- // policy if no results are produced yet.
- TEST_P(CdsTest, RingHashContinuesPastTerminalPolicyThatDoesNotProduceResult) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("header_not_present");
- hash_policy->set_terminal(true);
- auto* hash_policy2 = route->mutable_route()->add_hash_policy();
- hash_policy2->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 2)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- CheckRpcSendOk(100, rpc_options);
- EXPECT_EQ(backends_[0]->backend_service()->request_count(), 100);
- EXPECT_EQ(backends_[1]->backend_service()->request_count(), 0);
- }
- // Test random hash is used when header hashing specified a header field that
- // the RPC did not have.
- TEST_P(CdsTest, RingHashOnHeaderThatIsNotPresent) {
- const double kDistribution50Percent = 0.5;
- const double kErrorTolerance = 0.05;
- const uint32_t kRpcTimeoutMs = 10000;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kDistribution50Percent, kErrorTolerance);
- auto cluster = default_cluster_;
- // Increasing min ring size for random distribution.
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 100000);
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("header_not_present");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 2)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"unmatched_header", absl::StrFormat("%" PRIu32, rand())},
- };
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- // TODO(donnadionne): remove extended timeout after ring creation
- // optimization.
- WaitForAllBackends(0, 2, WaitForBackendOptions(),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- CheckRpcSendOk(kNumRpcs, rpc_options);
- const int request_count_1 = backends_[0]->backend_service()->request_count();
- const int request_count_2 = backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(request_count_1) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- }
- // Test random hash is used when only unsupported hash policies are
- // configured.
- TEST_P(CdsTest, RingHashUnsupportedHashPolicyDefaultToRandomHashing) {
- const double kDistribution50Percent = 0.5;
- const double kErrorTolerance = 0.05;
- const uint32_t kRpcTimeoutMs = 10000;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kDistribution50Percent, kErrorTolerance);
- auto cluster = default_cluster_;
- // Increasing min ring size for random distribution.
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 100000);
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy_unsupported_1 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_1->mutable_cookie()->set_name("cookie");
- auto* hash_policy_unsupported_2 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_2->mutable_connection_properties()->set_source_ip(
- true);
- auto* hash_policy_unsupported_3 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_3->mutable_query_parameter()->set_name(
- "query_parameter");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 2)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // TODO(donnadionne): remove extended timeout after ring creation
- // optimization.
- WaitForAllBackends(0, 2, WaitForBackendOptions(),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- CheckRpcSendOk(kNumRpcs);
- const int request_count_1 = backends_[0]->backend_service()->request_count();
- const int request_count_2 = backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(request_count_1) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(request_count_2) / kNumRpcs,
- ::testing::DoubleNear(kDistribution50Percent, kErrorTolerance));
- }
- // Tests that ring hash policy that hashes using a random value can spread
- // RPCs across all the backends according to locality weight.
- TEST_P(CdsTest, RingHashRandomHashingDistributionAccordingToEndpointWeight) {
- const size_t kWeight1 = 1;
- const size_t kWeight2 = 2;
- const size_t kWeightTotal = kWeight1 + kWeight2;
- const double kWeight33Percent = static_cast<double>(kWeight1) / kWeightTotal;
- const double kWeight66Percent = static_cast<double>(kWeight2) / kWeightTotal;
- const double kErrorTolerance = 0.05;
- const uint32_t kRpcTimeoutMs = 10000;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kWeight33Percent, kErrorTolerance);
- auto cluster = default_cluster_;
- // Increasing min ring size for random distribution.
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 100000);
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- EdsResourceArgs args({{"locality0",
- {CreateEndpoint(0, HealthStatus::UNKNOWN, 1),
- CreateEndpoint(1, HealthStatus::UNKNOWN, 2)}}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // TODO(donnadionne): remove extended timeout after ring creation
- // optimization.
- WaitForAllBackends(0, 2, WaitForBackendOptions(),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- CheckRpcSendOk(kNumRpcs);
- const int weight_33_request_count =
- backends_[0]->backend_service()->request_count();
- const int weight_66_request_count =
- backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(weight_33_request_count) / kNumRpcs,
- ::testing::DoubleNear(kWeight33Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_66_request_count) / kNumRpcs,
- ::testing::DoubleNear(kWeight66Percent, kErrorTolerance));
- }
- // Tests that ring hash policy that hashes using a random value can spread
- // RPCs across all the backends according to locality weight.
- TEST_P(CdsTest,
- RingHashRandomHashingDistributionAccordingToLocalityAndEndpointWeight) {
- const size_t kWeight1 = 1 * 1;
- const size_t kWeight2 = 2 * 2;
- const size_t kWeightTotal = kWeight1 + kWeight2;
- const double kWeight20Percent = static_cast<double>(kWeight1) / kWeightTotal;
- const double kWeight80Percent = static_cast<double>(kWeight2) / kWeightTotal;
- const double kErrorTolerance = 0.05;
- const uint32_t kRpcTimeoutMs = 10000;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kWeight20Percent, kErrorTolerance);
- auto cluster = default_cluster_;
- // Increasing min ring size for random distribution.
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 100000);
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- EdsResourceArgs args(
- {{"locality0", {CreateEndpoint(0, HealthStatus::UNKNOWN, 1)}, 1},
- {"locality1", {CreateEndpoint(1, HealthStatus::UNKNOWN, 2)}, 2}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // TODO(donnadionne): remove extended timeout after ring creation
- // optimization.
- WaitForAllBackends(0, 2, WaitForBackendOptions(),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- CheckRpcSendOk(kNumRpcs);
- const int weight_20_request_count =
- backends_[0]->backend_service()->request_count();
- const int weight_80_request_count =
- backends_[1]->backend_service()->request_count();
- EXPECT_THAT(static_cast<double>(weight_20_request_count) / kNumRpcs,
- ::testing::DoubleNear(kWeight20Percent, kErrorTolerance));
- EXPECT_THAT(static_cast<double>(weight_80_request_count) / kNumRpcs,
- ::testing::DoubleNear(kWeight80Percent, kErrorTolerance));
- }
- // Tests round robin is not implacted by the endpoint weight, and that the
- // localities in a locality map are picked according to their weights.
- TEST_P(CdsTest, RingHashEndpointWeightDoesNotImpactWeightedRoundRobin) {
- const int kLocalityWeight0 = 2;
- const int kLocalityWeight1 = 8;
- const int kTotalLocalityWeight = kLocalityWeight0 + kLocalityWeight1;
- const double kLocalityWeightRate0 =
- static_cast<double>(kLocalityWeight0) / kTotalLocalityWeight;
- const double kLocalityWeightRate1 =
- static_cast<double>(kLocalityWeight1) / kTotalLocalityWeight;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kLocalityWeightRate0, kErrorTolerance);
- // ADS response contains 2 localities, each of which contains 1 backend.
- EdsResourceArgs args({
- {"locality0",
- {CreateEndpoint(0, HealthStatus::UNKNOWN, 8)},
- kLocalityWeight0},
- {"locality1",
- {CreateEndpoint(1, HealthStatus::UNKNOWN, 2)},
- kLocalityWeight1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for both backends to be ready.
- WaitForAllBackends(0, 2);
- // Send kNumRpcs RPCs.
- CheckRpcSendOk(kNumRpcs);
- // The locality picking rates should be roughly equal to the expectation.
- const double locality_picked_rate_0 =
- static_cast<double>(backends_[0]->backend_service()->request_count()) /
- kNumRpcs;
- const double locality_picked_rate_1 =
- static_cast<double>(backends_[1]->backend_service()->request_count()) /
- kNumRpcs;
- EXPECT_THAT(locality_picked_rate_0,
- ::testing::DoubleNear(kLocalityWeightRate0, kErrorTolerance));
- EXPECT_THAT(locality_picked_rate_1,
- ::testing::DoubleNear(kLocalityWeightRate1, kErrorTolerance));
- }
- // Tests that ring hash policy that hashes using a fixed string ensures all
- // RPCs to go 1 particular backend; and that subsequent hashing policies are
- // ignored due to the setting of terminal.
- TEST_P(CdsTest, RingHashFixedHashingTerminalPolicy) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("fixed_string");
- hash_policy->set_terminal(true);
- auto* hash_policy_to_be_ignored = route->mutable_route()->add_hash_policy();
- hash_policy_to_be_ignored->mutable_header()->set_header_name("random_string");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"fixed_string", "fixed_value"},
- {"random_string", absl::StrFormat("%" PRIu32, rand())},
- };
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- CheckRpcSendOk(100, rpc_options);
- bool found = false;
- for (size_t i = 0; i < backends_.size(); ++i) {
- if (backends_[i]->backend_service()->request_count() > 0) {
- EXPECT_EQ(backends_[i]->backend_service()->request_count(), 100)
- << "backend " << i;
- EXPECT_FALSE(found) << "backend " << i;
- found = true;
- }
- }
- EXPECT_TRUE(found);
- }
- // Test that the channel will go from idle to ready via connecting;
- // (tho it is not possible to catch the connecting state before moving to
- // ready)
- TEST_P(CdsTest, RingHashIdleToReady) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
- CheckRpcSendOk();
- EXPECT_EQ(GRPC_CHANNEL_READY, channel_->GetState(false));
- }
- // Test that when the first pick is down leading to a transient failure, we
- // will move on to the next ring hash entry.
- TEST_P(CdsTest, RingHashTransientFailureCheckNextOne) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- std::vector<EdsResourceArgs::Endpoint> endpoints;
- const int unused_port = grpc_pick_unused_port_or_die();
- endpoints.emplace_back(unused_port);
- endpoints.emplace_back(backends_[1]->port());
- EdsResourceArgs args({
- {"locality0", std::move(endpoints)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash",
- CreateMetadataValueThatHashesToBackendPort(unused_port)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- WaitForBackend(1, WaitForBackendOptions(), rpc_options);
- CheckRpcSendOk(100, rpc_options);
- EXPECT_EQ(0, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(100, backends_[1]->backend_service()->request_count());
- }
- // Test that when a backend goes down, we will move on to the next subchannel
- // (with a lower priority). When the backend comes back up, traffic will move
- // back.
- TEST_P(CdsTest, RingHashSwitchToLowerPrioirtyAndThenBack) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- WaitForBackend(0, WaitForBackendOptions(), rpc_options);
- ShutdownBackend(0);
- WaitForBackend(1, WaitForBackendOptions().set_allow_failures(true),
- rpc_options);
- StartBackend(0);
- WaitForBackend(0, WaitForBackendOptions(), rpc_options);
- CheckRpcSendOk(100, rpc_options);
- EXPECT_EQ(100, backends_[0]->backend_service()->request_count());
- EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
- }
- // Test that when all backends are down, we will keep reattempting.
- TEST_P(CdsTest, RingHashAllFailReattempt) {
- const uint32_t kConnectionTimeoutMilliseconds = 5000;
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- std::vector<EdsResourceArgs::Endpoint> endpoints;
- endpoints.emplace_back(grpc_pick_unused_port_or_die());
- endpoints.emplace_back(backends_[1]->port());
- EdsResourceArgs args({
- {"locality0", std::move(endpoints)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
- ShutdownBackend(1);
- CheckRpcSendFailure(CheckRpcSendFailureOptions().set_rpc_options(
- RpcOptions().set_metadata(std::move(metadata))));
- StartBackend(1);
- // Ensure we are actively connecting without any traffic.
- EXPECT_TRUE(channel_->WaitForConnected(
- grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds)));
- }
- // Test that when all backends are down and then up, we may pick a TF backend
- // and we will then jump to ready backend.
- TEST_P(CdsTest, RingHashTransientFailureSkipToAvailableReady) {
- const uint32_t kConnectionTimeoutMilliseconds = 5000;
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_header()->set_header_name("address_hash");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- std::vector<EdsResourceArgs::Endpoint> endpoints;
- // Make sure we include some unused ports to fill the ring.
- endpoints.emplace_back(backends_[0]->port());
- endpoints.emplace_back(backends_[1]->port());
- endpoints.emplace_back(grpc_pick_unused_port_or_die());
- endpoints.emplace_back(grpc_pick_unused_port_or_die());
- EdsResourceArgs args({
- {"locality0", std::move(endpoints)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"address_hash", CreateMetadataValueThatHashesToBackend(0)}};
- const auto rpc_options = RpcOptions().set_metadata(std::move(metadata));
- EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
- ShutdownBackend(0);
- ShutdownBackend(1);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions().set_rpc_options(rpc_options));
- EXPECT_EQ(GRPC_CHANNEL_TRANSIENT_FAILURE, channel_->GetState(false));
- // Bring up 0, should be picked as the RPC is hashed to it.
- StartBackend(0);
- EXPECT_TRUE(channel_->WaitForConnected(
- grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds)));
- WaitForBackend(0, WaitForBackendOptions(), rpc_options);
- // Bring down 0 and bring up 1.
- // Note the RPC contains a header value that will always be hashed to
- // backend 0. So by purposely bring down backend 0 and bring up another
- // backend, this will ensure Picker's first choice of backend 0 will fail
- // and it will
- // 1. reattempt backend 0 and
- // 2. go through the remaining subchannels to find one in READY.
- // Since the the entries in the ring is pretty distributed and we have
- // unused ports to fill the ring, it is almost guaranteed that the Picker
- // will go through some non-READY entries and skip them as per design.
- ShutdownBackend(0);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions().set_rpc_options(rpc_options));
- StartBackend(1);
- EXPECT_TRUE(channel_->WaitForConnected(
- grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds)));
- WaitForBackend(1, WaitForBackendOptions(), rpc_options);
- }
- // Test unspported hash policy types are all ignored before a supported
- // policy.
- TEST_P(CdsTest, RingHashUnsupportedHashPolicyUntilChannelIdHashing) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy_unsupported_1 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_1->mutable_cookie()->set_name("cookie");
- auto* hash_policy_unsupported_2 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_2->mutable_connection_properties()->set_source_ip(
- true);
- auto* hash_policy_unsupported_3 = route->mutable_route()->add_hash_policy();
- hash_policy_unsupported_3->mutable_query_parameter()->set_name(
- "query_parameter");
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- CheckRpcSendOk(100);
- bool found = false;
- for (size_t i = 0; i < backends_.size(); ++i) {
- if (backends_[i]->backend_service()->request_count() > 0) {
- EXPECT_EQ(backends_[i]->backend_service()->request_count(), 100)
- << "backend " << i;
- EXPECT_FALSE(found) << "backend " << i;
- found = true;
- }
- }
- EXPECT_TRUE(found);
- }
- // Test we nack when ring hash policy has invalid hash function (something
- // other than XX_HASH.
- TEST_P(CdsTest, RingHashPolicyHasInvalidHashFunction) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- cluster.mutable_ring_hash_lb_config()->set_hash_function(
- Cluster::RingHashLbConfig::MURMUR_HASH_2);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("ring hash lb config has invalid hash function."));
- }
- // Test we nack when ring hash policy has invalid ring size.
- TEST_P(CdsTest, RingHashPolicyHasInvalidMinimumRingSize) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 0);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "min_ring_size is not in the range of 1 to 8388608."));
- }
- // Test we nack when ring hash policy has invalid ring size.
- TEST_P(CdsTest, RingHashPolicyHasInvalidMaxmumRingSize) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- cluster.mutable_ring_hash_lb_config()->mutable_maximum_ring_size()->set_value(
- 8388609);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "max_ring_size is not in the range of 1 to 8388608."));
- }
- // Test we nack when ring hash policy has invalid ring size.
- TEST_P(CdsTest, RingHashPolicyHasInvalidRingSizeMinGreaterThanMax) {
- auto cluster = default_cluster_;
- cluster.set_lb_policy(Cluster::RING_HASH);
- cluster.mutable_ring_hash_lb_config()->mutable_maximum_ring_size()->set_value(
- 5000);
- cluster.mutable_ring_hash_lb_config()->mutable_minimum_ring_size()->set_value(
- 5001);
- balancer_->ads_service()->SetCdsResource(cluster);
- auto new_route_config = default_route_config_;
- auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- auto* hash_policy = route->mutable_route()->add_hash_policy();
- hash_policy->mutable_filter_state()->set_key("io.grpc.channel_id");
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "min_ring_size cannot be greater than max_ring_size."));
- }
- class XdsSecurityTest : public BasicTest {
- protected:
- void SetUp() override {
- BootstrapBuilder builder = BootstrapBuilder();
- builder.AddCertificateProviderPlugin("fake_plugin1", "fake1");
- builder.AddCertificateProviderPlugin("fake_plugin2", "fake2");
- std::vector<std::string> fields;
- fields.push_back(absl::StrFormat(" \"certificate_file\": \"%s\"",
- kClientCertPath));
- fields.push_back(absl::StrFormat(" \"private_key_file\": \"%s\"",
- kClientKeyPath));
- fields.push_back(absl::StrFormat(" \"ca_certificate_file\": \"%s\"",
- kCaCertPath));
- builder.AddCertificateProviderPlugin("file_plugin", "file_watcher",
- absl::StrJoin(fields, ",\n"));
- CreateClientsAndServers(builder);
- StartAllBackends();
- root_cert_ = ReadFile(kCaCertPath);
- bad_root_cert_ = ReadFile(kBadClientCertPath);
- identity_pair_ = ReadTlsIdentityPair(kClientKeyPath, kClientCertPath);
- // TODO(yashykt): Use different client certs here instead of reusing
- // server certs after https://github.com/grpc/grpc/pull/24876 is merged
- fallback_identity_pair_ =
- ReadTlsIdentityPair(kServerKeyPath, kServerCertPath);
- bad_identity_pair_ =
- ReadTlsIdentityPair(kBadClientKeyPath, kBadClientCertPath);
- server_san_exact_.set_exact("*.test.google.fr");
- server_san_prefix_.set_prefix("waterzooi.test.google");
- server_san_suffix_.set_suffix("google.fr");
- server_san_contains_.set_contains("google");
- server_san_regex_.mutable_safe_regex()->mutable_google_re2();
- server_san_regex_.mutable_safe_regex()->set_regex(
- "(foo|waterzooi).test.google.(fr|be)");
- bad_san_1_.set_exact("192.168.1.4");
- bad_san_2_.set_exact("foo.test.google.in");
- authenticated_identity_ = {"testclient"};
- fallback_authenticated_identity_ = {"*.test.google.fr",
- "waterzooi.test.google.be",
- "*.test.youtube.com", "192.168.1.3"};
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- }
- void TearDown() override {
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- XdsEnd2endTest::TearDown();
- }
- // Sends CDS updates with the new security configuration and verifies that
- // after propagation, this new configuration is used for connections. If \a
- // identity_instance_name and \a root_instance_name are both empty,
- // connections are expected to use fallback credentials.
- void UpdateAndVerifyXdsSecurityConfiguration(
- absl::string_view root_instance_name,
- absl::string_view root_certificate_name,
- absl::string_view identity_instance_name,
- absl::string_view identity_certificate_name,
- const std::vector<StringMatcher>& san_matchers,
- const std::vector<std::string>& expected_authenticated_identity,
- bool test_expects_failure = false) {
- auto cluster = default_cluster_;
- if (!identity_instance_name.empty() || !root_instance_name.empty()) {
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- if (!identity_instance_name.empty()) {
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name(std::string(identity_instance_name));
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_certificate_name(std::string(identity_certificate_name));
- }
- if (!root_instance_name.empty()) {
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name(std::string(root_instance_name));
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_certificate_name(std::string(root_certificate_name));
- }
- if (!san_matchers.empty()) {
- auto* validation_context =
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context();
- for (const auto& san_matcher : san_matchers) {
- *validation_context->add_match_subject_alt_names() = san_matcher;
- }
- }
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- }
- balancer_->ads_service()->SetCdsResource(cluster);
- // The updates might take time to have an effect, so use a retry loop.
- constexpr int kRetryCount = 100;
- int num_tries = 0;
- for (; num_tries < kRetryCount; num_tries++) {
- // Give some time for the updates to propagate.
- gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
- if (test_expects_failure) {
- // Restart the servers to force a reconnection so that previously
- // connected subchannels are not used for the RPC.
- ShutdownBackend(0);
- StartBackend(0);
- if (SendRpc().ok()) {
- gpr_log(GPR_ERROR, "RPC succeeded. Failure expected. Trying again.");
- continue;
- }
- } else {
- WaitForBackend(0, WaitForBackendOptions().set_allow_failures(true));
- Status status = SendRpc();
- if (!status.ok()) {
- gpr_log(GPR_ERROR, "RPC failed. code=%d message=%s Trying again.",
- status.error_code(), status.error_message().c_str());
- continue;
- }
- if (backends_[0]->backend_service()->last_peer_identity() !=
- expected_authenticated_identity) {
- gpr_log(
- GPR_ERROR,
- "Expected client identity does not match. (actual) %s vs "
- "(expected) %s Trying again.",
- absl::StrJoin(
- backends_[0]->backend_service()->last_peer_identity(), ",")
- .c_str(),
- absl::StrJoin(expected_authenticated_identity, ",").c_str());
- continue;
- }
- }
- break;
- }
- EXPECT_LT(num_tries, kRetryCount);
- }
- std::string root_cert_;
- std::string bad_root_cert_;
- grpc_core::PemKeyCertPairList identity_pair_;
- grpc_core::PemKeyCertPairList fallback_identity_pair_;
- grpc_core::PemKeyCertPairList bad_identity_pair_;
- StringMatcher server_san_exact_;
- StringMatcher server_san_prefix_;
- StringMatcher server_san_suffix_;
- StringMatcher server_san_contains_;
- StringMatcher server_san_regex_;
- StringMatcher bad_san_1_;
- StringMatcher bad_san_2_;
- std::vector<std::string> authenticated_identity_;
- std::vector<std::string> fallback_authenticated_identity_;
- };
- TEST_P(XdsSecurityTest, UnknownTransportSocket) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("unknown_transport_socket");
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized transport socket: unknown_transport_socket"));
- }
- TEST_P(XdsSecurityTest,
- TLSConfigurationWithoutValidationContextCertificateProviderInstance) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("TLS configuration provided but no "
- "ca_certificate_provider_instance found."));
- }
- TEST_P(
- XdsSecurityTest,
- MatchSubjectAltNamesProvidedWithoutValidationContextCertificateProviderInstance) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- auto* validation_context = upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context();
- *validation_context->add_match_subject_alt_names() = server_san_exact_;
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("TLS configuration provided but no "
- "ca_certificate_provider_instance found."));
- }
- TEST_P(
- XdsSecurityTest,
- TlsCertificateProviderInstanceWithoutValidationContextCertificateProviderInstance) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name(std::string("fake_plugin1"));
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("TLS configuration provided but no "
- "ca_certificate_provider_instance found."));
- }
- TEST_P(XdsSecurityTest, RegexSanMatcherDoesNotAllowIgnoreCase) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name(std::string("fake_plugin1"));
- auto* validation_context = upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context();
- StringMatcher matcher;
- matcher.mutable_safe_regex()->mutable_google_re2();
- matcher.mutable_safe_regex()->set_regex(
- "(foo|waterzooi).test.google.(fr|be)");
- matcher.set_ignore_case(true);
- *validation_context->add_match_subject_alt_names() = matcher;
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "StringMatcher: ignore_case has no effect for SAFE_REGEX."));
- }
- TEST_P(XdsSecurityTest, UnknownRootCertificateProvider) {
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("unknown");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized certificate provider instance name: unknown"));
- }
- TEST_P(XdsSecurityTest, UnknownIdentityCertificateProvider) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("unknown");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized certificate provider instance name: unknown"));
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest,
- NacksCertificateValidationContextWithVerifyCertificateSpki) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->add_verify_certificate_spki("spki");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "CertificateValidationContext: verify_certificate_spki unsupported"));
- }
- TEST_P(XdsSecurityTest,
- NacksCertificateValidationContextWithVerifyCertificateHash) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->add_verify_certificate_hash("hash");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "CertificateValidationContext: verify_certificate_hash unsupported"));
- }
- TEST_P(XdsSecurityTest,
- NacksCertificateValidationContextWithRequireSignedCertificateTimes) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_require_signed_certificate_timestamp()
- ->set_value(true);
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("CertificateValidationContext: "
- "require_signed_certificate_timestamp unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksCertificateValidationContextWithCrl) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_crl();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("CertificateValidationContext: crl unsupported"));
- }
- TEST_P(XdsSecurityTest,
- NacksCertificateValidationContextWithCustomValidatorConfig) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_custom_validator_config();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "CertificateValidationContext: custom_validator_config unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksValidationContextSdsSecretConfig) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context_sds_secret_config();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("validation_context_sds_secret_config unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksTlsParams) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()->mutable_tls_params();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("tls_params unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksCustomHandshaker) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_custom_handshaker();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("custom_handshaker unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksTlsCertificates) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()->add_tls_certificates();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("tls_certificates unsupported"));
- }
- TEST_P(XdsSecurityTest, NacksTlsCertificateSdsSecretConfigs) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- upstream_tls_context.mutable_common_tls_context()
- ->add_tls_certificate_sds_secret_configs();
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- const auto response_state = WaitForCdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("tls_certificate_sds_secret_configs unsupported"));
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationInCombinedValidationContext) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_combined_validation_context()
- ->mutable_default_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- WaitForBackend(0, WaitForBackendOptions().set_allow_failures(true));
- Status status = SendRpc();
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- // TODO(yashykt): Remove this test once we stop supporting old fields
- TEST_P(XdsSecurityTest,
- TestTlsConfigurationInValidationContextCertificateProviderInstance) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- auto cluster = default_cluster_;
- auto* transport_socket = cluster.mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- UpstreamTlsContext upstream_tls_context;
- upstream_tls_context.mutable_common_tls_context()
- ->mutable_combined_validation_context()
- ->mutable_validation_context_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
- balancer_->ads_service()->SetCdsResource(cluster);
- WaitForBackend(0, WaitForBackendOptions().set_allow_failures(true));
- Status status = SendRpc();
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithNoSanMatchers) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {}, authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithExactSanMatcher) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithPrefixSanMatcher) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_prefix_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithSuffixSanMatcher) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_suffix_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithContainsSanMatcher) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_contains_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRegexSanMatcher) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_regex_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithSanMatchersUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "fake_plugin1", "",
- {server_san_exact_, server_san_prefix_}, authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {bad_san_1_, bad_san_2_}, {},
- true /* failure */);
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "fake_plugin1", "",
- {server_san_prefix_, server_san_regex_}, authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {bad_root_cert_, bad_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2" /* bad root */, "",
- "fake_plugin1", "", {}, {},
- true /* failure */);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithIdentityPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {root_cert_, fallback_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin2",
- "", {server_san_exact_},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothPluginsUpdated) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {bad_root_cert_, bad_identity_pair_}},
- {"good", {root_cert_, fallback_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "", "fake_plugin2",
- "", {}, {}, true /* failure */);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_prefix_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin2", "good", "fake_plugin2", "good", {server_san_prefix_},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"bad", {bad_root_cert_, bad_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_regex_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1",
- "", {server_san_regex_}, {},
- true /* failure */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest,
- TestMtlsConfigurationWithIdentityCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"bad", {bad_root_cert_, bad_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "bad", {server_san_exact_}, {},
- true /* failure */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest,
- TestMtlsConfigurationWithIdentityCertificateNameUpdateGoodCerts) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"good", {root_cert_, fallback_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "good", {server_san_exact_},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothCertificateNamesUpdated) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"bad", {bad_root_cert_, bad_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1",
- "bad", {server_san_prefix_}, {},
- true /* failure */);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_prefix_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationWithNoSanMatchers) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "", {},
- {} /* unauthenticated */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationWithSanMatchers) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "", "",
- {server_san_exact_, server_san_prefix_, server_san_regex_},
- {} /* unauthenticated */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationWithSanMatchersUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "", "", {server_san_exact_, server_san_prefix_},
- {} /* unauthenticated */);
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "", "", {bad_san_1_, bad_san_2_},
- {} /* unauthenticated */, true /* failure */);
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin1", "", "", "", {server_san_prefix_, server_san_regex_},
- {} /* unauthenticated */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"bad", {bad_root_cert_, bad_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "", "",
- {server_san_exact_}, {},
- true /* failure */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {bad_root_cert_, bad_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- UpdateAndVerifyXdsSecurityConfiguration(
- "fake_plugin2", "", "", "", {server_san_exact_}, {}, true /* failure */);
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestFallbackConfiguration) {
- UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsToTls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestMtlsToFallback) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsToMtls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestTlsToFallback) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {},
- fallback_authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestFallbackToMtls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {},
- fallback_authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
- "", {server_san_exact_},
- authenticated_identity_);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestFallbackToTls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- UpdateAndVerifyXdsSecurityConfiguration("", "", "", "", {},
- fallback_authenticated_identity_);
- UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
- {server_san_exact_},
- {} /* unauthenticated */);
- g_fake1_cert_data_map = nullptr;
- }
- TEST_P(XdsSecurityTest, TestFileWatcherCertificateProvider) {
- UpdateAndVerifyXdsSecurityConfiguration("file_plugin", "", "file_plugin", "",
- {server_san_exact_},
- authenticated_identity_);
- }
- class XdsEnabledServerTest : public XdsEnd2endTest {
- protected:
- XdsEnabledServerTest()
- : XdsEnd2endTest(1, 100, 0, true /* use_xds_enabled_server */) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- }
- };
- TEST_P(XdsEnabledServerTest, Basic) {
- backends_[0]->Start();
- WaitForBackend(0);
- }
- TEST_P(XdsEnabledServerTest, BadLdsUpdateNoApiListenerNorAddress) {
- Listener listener = default_server_listener_;
- listener.clear_address();
- listener.set_name(
- absl::StrCat("grpc/server?xds.resource.listening_address=",
- ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()));
- balancer_->ads_service()->SetLdsResource(listener);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Listener has neither address nor ApiListener"));
- }
- TEST_P(XdsEnabledServerTest, BadLdsUpdateBothApiListenerAndAddress) {
- Listener listener = default_server_listener_;
- listener.mutable_api_listener();
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Listener has both address and ApiListener"));
- }
- TEST_P(XdsEnabledServerTest, NacksNonZeroXffNumTrusterHops) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.set_xff_num_trusted_hops(1);
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'xff_num_trusted_hops' must be zero"));
- }
- TEST_P(XdsEnabledServerTest, NacksNonEmptyOriginalIpDetectionExtensions) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.add_original_ip_detection_extensions();
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("'original_ip_detection_extensions' must be empty"));
- }
- TEST_P(XdsEnabledServerTest, UnsupportedL4Filter) {
- Listener listener = default_server_listener_;
- listener.mutable_default_filter_chain()->clear_filters();
- listener.mutable_default_filter_chain()->add_filters()->mutable_typed_config()->PackFrom(default_listener_ /* any proto object other than HttpConnectionManager */);
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Unsupported filter type"));
- }
- TEST_P(XdsEnabledServerTest, NacksEmptyHttpFilterList) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.clear_http_filters();
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Expected at least one HTTP filter"));
- }
- TEST_P(XdsEnabledServerTest, UnsupportedHttpFilter) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.clear_http_filters();
- auto* http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("grpc.testing.unsupported_http_filter");
- http_filter->mutable_typed_config()->set_type_url(
- "grpc.testing.unsupported_http_filter");
- http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("router");
- http_filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("no filter registered for config type "
- "grpc.testing.unsupported_http_filter"));
- }
- TEST_P(XdsEnabledServerTest, HttpFilterNotSupportedOnServer) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.clear_http_filters();
- auto* http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("grpc.testing.client_only_http_filter");
- http_filter->mutable_typed_config()->set_type_url(
- "grpc.testing.client_only_http_filter");
- http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("router");
- http_filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Filter grpc.testing.client_only_http_filter is not "
- "supported on servers"));
- }
- TEST_P(XdsEnabledServerTest,
- HttpFilterNotSupportedOnServerIgnoredWhenOptional) {
- Listener listener = default_server_listener_;
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.clear_http_filters();
- auto* http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("grpc.testing.client_only_http_filter");
- http_filter->mutable_typed_config()->set_type_url(
- "grpc.testing.client_only_http_filter");
- http_filter->set_is_optional(true);
- http_filter = http_connection_manager.add_http_filters();
- http_filter->set_name("router");
- http_filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- WaitForBackend(0);
- auto response_state = balancer_->ads_service()->lds_response_state();
- ASSERT_TRUE(response_state.has_value());
- EXPECT_EQ(response_state->state, AdsServiceImpl::ResponseState::ACKED);
- }
- // Verify that a mismatch of listening address results in "not serving"
- // status.
- TEST_P(XdsEnabledServerTest, ListenerAddressMismatch) {
- Listener listener = default_server_listener_;
- // Set a different listening address in the LDS update
- listener.mutable_address()->mutable_socket_address()->set_address(
- "192.168.1.1");
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::FAILED_PRECONDITION);
- }
- TEST_P(XdsEnabledServerTest, UseOriginalDstNotSupported) {
- Listener listener = default_server_listener_;
- listener.mutable_use_original_dst()->set_value(true);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Field \'use_original_dst\' is not supported."));
- }
- class XdsServerSecurityTest : public XdsEnd2endTest {
- protected:
- XdsServerSecurityTest()
- : XdsEnd2endTest(1, 100, 0, true /* use_xds_enabled_server */) {}
- void SetUp() override {
- BootstrapBuilder builder = BootstrapBuilder();
- builder.AddCertificateProviderPlugin("fake_plugin1", "fake1");
- builder.AddCertificateProviderPlugin("fake_plugin2", "fake2");
- std::vector<std::string> fields;
- fields.push_back(absl::StrFormat(" \"certificate_file\": \"%s\"",
- kClientCertPath));
- fields.push_back(absl::StrFormat(" \"private_key_file\": \"%s\"",
- kClientKeyPath));
- fields.push_back(absl::StrFormat(" \"ca_certificate_file\": \"%s\"",
- kCaCertPath));
- builder.AddCertificateProviderPlugin("file_plugin", "file_watcher",
- absl::StrJoin(fields, ",\n"));
- CreateClientsAndServers(builder);
- root_cert_ = ReadFile(kCaCertPath);
- bad_root_cert_ = ReadFile(kBadClientCertPath);
- identity_pair_ = ReadTlsIdentityPair(kServerKeyPath, kServerCertPath);
- bad_identity_pair_ =
- ReadTlsIdentityPair(kBadClientKeyPath, kBadClientCertPath);
- identity_pair_2_ = ReadTlsIdentityPair(kClientKeyPath, kClientCertPath);
- server_authenticated_identity_ = {"*.test.google.fr",
- "waterzooi.test.google.be",
- "*.test.youtube.com", "192.168.1.3"};
- server_authenticated_identity_2_ = {"testclient"};
- client_authenticated_identity_ = {"*.test.google.fr",
- "waterzooi.test.google.be",
- "*.test.youtube.com", "192.168.1.3"};
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- }
- void TearDown() override {
- g_fake1_cert_data_map = nullptr;
- g_fake2_cert_data_map = nullptr;
- XdsEnd2endTest::TearDown();
- }
- void SetLdsUpdate(absl::string_view root_instance_name,
- absl::string_view root_certificate_name,
- absl::string_view identity_instance_name,
- absl::string_view identity_certificate_name,
- bool require_client_certificates) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- if (!identity_instance_name.empty()) {
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name(std::string(identity_instance_name));
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_certificate_name(std::string(identity_certificate_name));
- if (!root_instance_name.empty()) {
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name(std::string(root_instance_name));
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_certificate_name(std::string(root_certificate_name));
- downstream_tls_context.mutable_require_client_certificate()->set_value(
- require_client_certificates);
- }
- transport_socket->mutable_typed_config()->PackFrom(
- downstream_tls_context);
- }
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- }
- std::shared_ptr<grpc::Channel> CreateMtlsChannel() {
- ChannelArguments args;
- // Override target name for host name check
- args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
- ipv6_only_ ? "::1" : "127.0.0.1");
- args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
- std::string uri = absl::StrCat(
- ipv6_only_ ? "ipv6:[::1]:" : "ipv4:127.0.0.1:", backends_[0]->port());
- IdentityKeyCertPair key_cert_pair;
- key_cert_pair.private_key = ReadFile(kServerKeyPath);
- key_cert_pair.certificate_chain = ReadFile(kServerCertPath);
- std::vector<IdentityKeyCertPair> identity_key_cert_pairs;
- identity_key_cert_pairs.emplace_back(key_cert_pair);
- auto certificate_provider = std::make_shared<StaticDataCertificateProvider>(
- ReadFile(kCaCertPath), identity_key_cert_pairs);
- grpc::experimental::TlsChannelCredentialsOptions options;
- options.set_certificate_provider(std::move(certificate_provider));
- options.watch_root_certs();
- options.watch_identity_key_cert_pairs();
- auto verifier =
- ExternalCertificateVerifier::Create<SyncCertificateVerifier>(true);
- options.set_verify_server_certs(true);
- options.set_certificate_verifier(std::move(verifier));
- auto channel_creds = grpc::experimental::TlsCredentials(options);
- GPR_ASSERT(channel_creds.get() != nullptr);
- return CreateCustomChannel(uri, channel_creds, args);
- }
- std::shared_ptr<grpc::Channel> CreateTlsChannel() {
- ChannelArguments args;
- // Override target name for host name check
- args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
- ipv6_only_ ? "::1" : "127.0.0.1");
- args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
- std::string uri = absl::StrCat(
- ipv6_only_ ? "ipv6:[::1]:" : "ipv4:127.0.0.1:", backends_[0]->port());
- auto certificate_provider =
- std::make_shared<StaticDataCertificateProvider>(ReadFile(kCaCertPath));
- grpc::experimental::TlsChannelCredentialsOptions options;
- options.set_certificate_provider(std::move(certificate_provider));
- options.watch_root_certs();
- auto verifier =
- ExternalCertificateVerifier::Create<SyncCertificateVerifier>(true);
- options.set_verify_server_certs(true);
- options.set_certificate_verifier(std::move(verifier));
- auto channel_creds = grpc::experimental::TlsCredentials(options);
- GPR_ASSERT(channel_creds.get() != nullptr);
- return CreateCustomChannel(uri, channel_creds, args);
- }
- std::shared_ptr<grpc::Channel> CreateInsecureChannel() {
- ChannelArguments args;
- // Override target name for host name check
- args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
- ipv6_only_ ? "::1" : "127.0.0.1");
- args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1);
- std::string uri = absl::StrCat(
- ipv6_only_ ? "ipv6:[::1]:" : "ipv4:127.0.0.1:", backends_[0]->port());
- return CreateCustomChannel(uri, InsecureChannelCredentials(), args);
- }
- void SendRpc(
- std::function<std::shared_ptr<grpc::Channel>()> channel_creator,
- std::vector<std::string> expected_server_identity,
- std::vector<std::string> expected_client_identity,
- bool test_expects_failure = false,
- absl::optional<grpc::StatusCode> expected_status = absl::nullopt) {
- gpr_log(GPR_INFO, "Sending RPC");
- int num_tries = 0;
- constexpr int kRetryCount = 100;
- auto overall_deadline = absl::Now() + absl::Seconds(5);
- for (; num_tries < kRetryCount || absl::Now() < overall_deadline;
- num_tries++) {
- auto channel = channel_creator();
- auto stub = grpc::testing::EchoTestService::NewStub(channel);
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- EchoRequest request;
- // TODO(yashykt): Skipping the cancelled check on the server since the
- // server's graceful shutdown isn't as per spec and the check isn't
- // necessary for what we want to test here anyway.
- // https://github.com/grpc/grpc/issues/24237
- request.mutable_param()->set_skip_cancelled_check(true);
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- if (test_expects_failure) {
- if (status.ok()) {
- gpr_log(GPR_ERROR, "RPC succeeded. Failure expected. Trying again.");
- continue;
- }
- if (expected_status.has_value() &&
- *expected_status != status.error_code()) {
- gpr_log(GPR_ERROR,
- "Expected status does not match Actual(%d) vs Expected(%d)",
- status.error_code(), *expected_status);
- continue;
- }
- } else {
- if (!status.ok()) {
- gpr_log(GPR_ERROR, "RPC failed. code=%d message=%s Trying again.",
- status.error_code(), status.error_message().c_str());
- continue;
- }
- EXPECT_EQ(response.message(), kRequestMessage);
- std::vector<std::string> peer_identity;
- for (const auto& entry : context.auth_context()->GetPeerIdentity()) {
- peer_identity.emplace_back(
- std::string(entry.data(), entry.size()).c_str());
- }
- if (peer_identity != expected_server_identity) {
- gpr_log(GPR_ERROR,
- "Expected server identity does not match. (actual) %s vs "
- "(expected) %s Trying again.",
- absl::StrJoin(peer_identity, ",").c_str(),
- absl::StrJoin(expected_server_identity, ",").c_str());
- continue;
- }
- if (backends_[0]->backend_service()->last_peer_identity() !=
- expected_client_identity) {
- gpr_log(
- GPR_ERROR,
- "Expected client identity does not match. (actual) %s vs "
- "(expected) %s Trying again.",
- absl::StrJoin(
- backends_[0]->backend_service()->last_peer_identity(), ",")
- .c_str(),
- absl::StrJoin(expected_client_identity, ",").c_str());
- continue;
- }
- }
- break;
- }
- EXPECT_LT(num_tries, kRetryCount);
- }
- std::string root_cert_;
- std::string bad_root_cert_;
- grpc_core::PemKeyCertPairList identity_pair_;
- grpc_core::PemKeyCertPairList bad_identity_pair_;
- grpc_core::PemKeyCertPairList identity_pair_2_;
- std::vector<std::string> server_authenticated_identity_;
- std::vector<std::string> server_authenticated_identity_2_;
- std::vector<std::string> client_authenticated_identity_;
- };
- TEST_P(XdsServerSecurityTest, UnknownTransportSocket) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("unknown_transport_socket");
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized transport socket: unknown_transport_socket"));
- }
- TEST_P(XdsServerSecurityTest, NacksRequireSNI) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.mutable_require_sni()->set_value(true);
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("require_sni: unsupported"));
- }
- TEST_P(XdsServerSecurityTest, NacksOcspStaplePolicyOtherThanLenientStapling) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.set_ocsp_staple_policy(
- envoy::extensions::transport_sockets::tls::v3::
- DownstreamTlsContext_OcspStaplePolicy_STRICT_STAPLING);
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "ocsp_staple_policy: Only LENIENT_STAPLING supported"));
- }
- TEST_P(
- XdsServerSecurityTest,
- NacksRequiringClientCertificateWithoutValidationCertificateProviderInstance) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.mutable_require_client_certificate()->set_value(true);
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "TLS configuration requires client certificates but no "
- "certificate provider instance specified for validation."));
- }
- TEST_P(XdsServerSecurityTest,
- NacksTlsConfigurationWithoutIdentityProviderInstance) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("TLS configuration provided but no "
- "tls_certificate_provider_instance found."));
- }
- TEST_P(XdsServerSecurityTest, NacksMatchSubjectAltNames) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->add_match_subject_alt_names()
- ->set_exact("*.test.google.fr");
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("match_subject_alt_names not supported on servers"));
- }
- TEST_P(XdsServerSecurityTest, UnknownIdentityCertificateProvider) {
- SetLdsUpdate("", "", "unknown", "", false);
- SendRpc([this]() { return CreateTlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized certificate provider instance name: unknown"));
- }
- TEST_P(XdsServerSecurityTest, UnknownRootCertificateProvider) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- SetLdsUpdate("unknown", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr(
- "Unrecognized certificate provider instance name: unknown"));
- }
- TEST_P(XdsServerSecurityTest,
- TestDeprecateTlsCertificateCertificateProviderInstanceField) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- filter_chain->mutable_filters()->at(0).mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- }
- TEST_P(XdsServerSecurityTest, CertificatesNotAvailable) {
- FakeCertificateProvider::CertDataMap fake1_cert_map;
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerSecurityTest, TestMtls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithRootPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {bad_root_cert_, bad_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin2", "", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithIdentityPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {root_cert_, identity_pair_2_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin1", "", "fake_plugin2", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_2_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithBothPluginsUpdated) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"good", {root_cert_, identity_pair_2_}},
- {"", {bad_root_cert_, bad_identity_pair_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- SetLdsUpdate("fake_plugin2", "", "fake_plugin2", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin2", "good", "fake_plugin2", "good", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_2_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithRootCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"bad", {bad_root_cert_, bad_identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin1", "bad", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithIdentityCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"good", {root_cert_, identity_pair_2_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "good", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_2_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsWithBothCertificateNamesUpdated) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"good", {root_cert_, identity_pair_2_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("fake_plugin1", "good", "fake_plugin1", "good", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_2_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsNotRequiringButProvidingClientCerts) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsNotRequiringAndNotProvidingClientCerts) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- }
- TEST_P(XdsServerSecurityTest, TestTls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- }
- TEST_P(XdsServerSecurityTest, TestTlsWithIdentityPluginUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- FakeCertificateProvider::CertDataMap fake2_cert_map = {
- {"", {root_cert_, identity_pair_2_}}};
- g_fake2_cert_data_map = &fake2_cert_map;
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- SetLdsUpdate("", "", "fake_plugin2", "", false);
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_2_, {});
- }
- TEST_P(XdsServerSecurityTest, TestTlsWithIdentityCertificateNameUpdate) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}},
- {"good", {root_cert_, identity_pair_2_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- SetLdsUpdate("", "", "fake_plugin1", "good", false);
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_2_, {});
- }
- TEST_P(XdsServerSecurityTest, TestFallback) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerSecurityTest, TestMtlsToTls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- }
- TEST_P(XdsServerSecurityTest, TestTlsToMtls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateTlsChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerSecurityTest, TestMtlsToFallback) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- SetLdsUpdate("", "", "", "", false);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerSecurityTest, TestFallbackToMtls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- SetLdsUpdate("fake_plugin1", "", "fake_plugin1", "", true);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_);
- }
- TEST_P(XdsServerSecurityTest, TestTlsToFallback) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- SetLdsUpdate("", "", "", "", false);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerSecurityTest, TestFallbackToTls) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- SetLdsUpdate("", "", "", "", false);
- backends_[0]->Start();
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- }
- class XdsEnabledServerStatusNotificationTest : public XdsServerSecurityTest {
- protected:
- void SetValidLdsUpdate() { SetLdsUpdate("", "", "", "", false); }
- void SetInvalidLdsUpdate() {
- Listener listener = default_server_listener_;
- listener.clear_address();
- listener.set_name(absl::StrCat(
- "grpc/server?xds.resource.listening_address=",
- ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()));
- balancer_->ads_service()->SetLdsResource(listener);
- }
- void UnsetLdsUpdate() {
- balancer_->ads_service()->UnsetResource(
- kLdsTypeUrl, absl::StrCat("grpc/server?xds.resource.listening_address=",
- ipv6_only_ ? "[::1]:" : "127.0.0.1:",
- backends_[0]->port()));
- }
- };
- TEST_P(XdsEnabledServerStatusNotificationTest, ServingStatus) {
- SetValidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsEnabledServerStatusNotificationTest, NotServingStatus) {
- SetInvalidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::UNAVAILABLE);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsEnabledServerStatusNotificationTest, ErrorUpdateWhenAlreadyServing) {
- SetValidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- // Invalid update does not lead to a change in the serving status.
- SetInvalidLdsUpdate();
- do {
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- } while (!balancer_->ads_service()->lds_response_state().has_value());
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsEnabledServerStatusNotificationTest,
- NotServingStatusToServingStatusTransition) {
- SetInvalidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::UNAVAILABLE);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- // Send a valid LDS update to change to serving status
- SetValidLdsUpdate();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- // This test verifies that the resource getting deleted when already serving
- // results in future connections being dropped.
- TEST_P(XdsEnabledServerStatusNotificationTest,
- ServingStatusToNonServingStatusTransition) {
- SetValidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- // Deleting the resource should result in a non-serving status.
- UnsetLdsUpdate();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::NOT_FOUND);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsEnabledServerStatusNotificationTest, RepeatedServingStatusChanges) {
- backends_[0]->Start();
- for (int i = 0; i < 5; i++) {
- // Send a valid LDS update to get the server to start listening
- SetValidLdsUpdate();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:",
- backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- // Deleting the resource will make the server start rejecting connections
- UnsetLdsUpdate();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:",
- backends_[0]->port()),
- grpc::StatusCode::NOT_FOUND);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- }
- TEST_P(XdsEnabledServerStatusNotificationTest, ExistingRpcsOnResourceDeletion) {
- // Send a valid LDS update to get the server to start listening
- SetValidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- constexpr int kNumChannels = 10;
- struct StreamingRpc {
- std::shared_ptr<Channel> channel;
- std::unique_ptr<grpc::testing::EchoTestService::Stub> stub;
- ClientContext context;
- std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream;
- } streaming_rpcs[kNumChannels];
- EchoRequest request;
- EchoResponse response;
- request.set_message("Hello");
- for (int i = 0; i < kNumChannels; i++) {
- streaming_rpcs[i].channel = CreateInsecureChannel();
- streaming_rpcs[i].stub =
- grpc::testing::EchoTestService::NewStub(streaming_rpcs[i].channel);
- streaming_rpcs[i].context.set_wait_for_ready(true);
- streaming_rpcs[i].stream =
- streaming_rpcs[i].stub->BidiStream(&streaming_rpcs[i].context);
- EXPECT_TRUE(streaming_rpcs[i].stream->Write(request));
- streaming_rpcs[i].stream->Read(&response);
- EXPECT_EQ(request.message(), response.message());
- }
- // Deleting the resource will make the server start rejecting connections
- UnsetLdsUpdate();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::NOT_FOUND);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- for (int i = 0; i < kNumChannels; i++) {
- EXPECT_TRUE(streaming_rpcs[i].stream->Write(request));
- streaming_rpcs[i].stream->Read(&response);
- EXPECT_EQ(request.message(), response.message());
- EXPECT_TRUE(streaming_rpcs[i].stream->WritesDone());
- auto status = streaming_rpcs[i].stream->Finish();
- EXPECT_TRUE(status.ok())
- << status.error_message() << ", " << status.error_details() << ", "
- << streaming_rpcs[i].context.debug_error_string();
- // New RPCs on the existing channels should fail.
- ClientContext new_context;
- new_context.set_deadline(grpc_timeout_milliseconds_to_deadline(1000));
- EXPECT_FALSE(
- streaming_rpcs[i].stub->Echo(&new_context, request, &response).ok());
- }
- }
- TEST_P(XdsEnabledServerStatusNotificationTest,
- ExistingRpcsFailOnResourceUpdateAfterDrainGraceTimeExpires) {
- constexpr int kDrainGraceTimeMs = 100;
- xds_drain_grace_time_ms_ = kDrainGraceTimeMs;
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- // Send a valid LDS update to get the server to start listening
- SetValidLdsUpdate();
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- constexpr int kNumChannels = 10;
- struct StreamingRpc {
- std::shared_ptr<Channel> channel;
- std::unique_ptr<grpc::testing::EchoTestService::Stub> stub;
- ClientContext context;
- std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream;
- } streaming_rpcs[kNumChannels];
- EchoRequest request;
- EchoResponse response;
- request.set_message("Hello");
- for (int i = 0; i < kNumChannels; i++) {
- streaming_rpcs[i].channel = CreateInsecureChannel();
- streaming_rpcs[i].stub =
- grpc::testing::EchoTestService::NewStub(streaming_rpcs[i].channel);
- streaming_rpcs[i].context.set_wait_for_ready(true);
- streaming_rpcs[i].stream =
- streaming_rpcs[i].stub->BidiStream(&streaming_rpcs[i].context);
- EXPECT_TRUE(streaming_rpcs[i].stream->Write(request));
- streaming_rpcs[i].stream->Read(&response);
- EXPECT_EQ(request.message(), response.message());
- }
- grpc_core::Timestamp update_time = NowFromCycleCounter();
- // Update the resource.
- SetLdsUpdate("", "", "fake_plugin1", "", false);
- // Wait for the updated resource to take effect.
- SendRpc([this]() { return CreateTlsChannel(); },
- server_authenticated_identity_, {});
- // After the drain grace time expires, the existing RPCs should all fail.
- for (int i = 0; i < kNumChannels; i++) {
- // Wait for the drain grace time to expire
- EXPECT_FALSE(streaming_rpcs[i].stream->Read(&response));
- // Make sure that the drain grace interval is honored.
- EXPECT_GE(NowFromCycleCounter() - update_time,
- grpc_core::Duration::Milliseconds(kDrainGraceTimeMs));
- auto status = streaming_rpcs[i].stream->Finish();
- EXPECT_EQ(status.error_code(), grpc::StatusCode::UNAVAILABLE)
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", "
- << streaming_rpcs[i].context.debug_error_string();
- }
- }
- using XdsServerFilterChainMatchTest = XdsServerSecurityTest;
- TEST_P(XdsServerFilterChainMatchTest,
- DefaultFilterChainUsedWhenNoFilterChainMentioned) {
- backends_[0]->Start();
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- DefaultFilterChainUsedWhenOtherFilterChainsDontMatch) {
- Listener listener = default_server_listener_;
- // Add a filter chain that will never get matched
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()
- ->mutable_destination_port()
- ->set_value(8080);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithDestinationPortDontMatch) {
- Listener listener = default_server_listener_;
- // Add filter chain with destination port that should never get matched
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()
- ->mutable_destination_port()
- ->set_value(8080);
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // RPC should fail since no matching filter chain was found and no default
- // filter chain is configured.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerFilterChainMatchTest, FilterChainsWithServerNamesDontMatch) {
- Listener listener = default_server_listener_;
- // Add filter chain with server name that should never get matched
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_server_names("server_name");
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // RPC should fail since no matching filter chain was found and no default
- // filter chain is configured.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithTransportProtocolsOtherThanRawBufferDontMatch) {
- Listener listener = default_server_listener_;
- // Add filter chain with transport protocol "tls" that should never match
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_transport_protocol("tls");
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // RPC should fail since no matching filter chain was found and no default
- // filter chain is configured.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithApplicationProtocolsDontMatch) {
- Listener listener = default_server_listener_;
- // Add filter chain with application protocol that should never get matched
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_application_protocols("h2");
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // RPC should fail since no matching filter chain was found and no default
- // filter chain is configured.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithTransportProtocolRawBufferIsPreferred) {
- Listener listener = default_server_listener_;
- // Add filter chain with "raw_buffer" transport protocol
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_transport_protocol(
- "raw_buffer");
- // Add another filter chain with no transport protocol set but application
- // protocol set (fails match)
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_application_protocols("h2");
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // A successful RPC proves that filter chains that mention "raw_buffer" as
- // the transport protocol are chosen as the best match in the round.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithMoreSpecificDestinationPrefixRangesArePreferred) {
- Listener listener = default_server_listener_;
- // Add filter chain with prefix range (length 4 and 16) but with server name
- // mentioned. (Prefix range is matched first.)
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(4);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(16);
- filter_chain->mutable_filter_chain_match()->add_server_names("server_name");
- // Add filter chain with two prefix ranges (length 8 and 24). Since 24 is
- // the highest match, it should be chosen.
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(8);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(24);
- // Add another filter chain with a non-matching prefix range (with length
- // 30)
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix("192.168.1.1");
- prefix_range->mutable_prefix_len()->set_value(30);
- filter_chain->mutable_filter_chain_match()->add_server_names("server_name");
- // Add another filter chain with no prefix range mentioned
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_server_names("server_name");
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // A successful RPC proves that the filter chain with the longest matching
- // prefix range was the best match.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsThatMentionSourceTypeArePreferred) {
- Listener listener = default_server_listener_;
- // Add filter chain with the local source type (best match)
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::SAME_IP_OR_LOOPBACK);
- // Add filter chain with the external source type but bad source port.
- // Note that backends_[0]->port() will never be a match for the source port
- // because it is already being used by a backend.
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::EXTERNAL);
- filter_chain->mutable_filter_chain_match()->add_source_ports(
- backends_[0]->port());
- // Add filter chain with the default source type (ANY) but bad source port.
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_source_ports(
- backends_[0]->port());
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // A successful RPC proves that the filter chain with the longest matching
- // prefix range was the best match.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithMoreSpecificSourcePrefixRangesArePreferred) {
- Listener listener = default_server_listener_;
- // Add filter chain with source prefix range (length 16) but with a bad
- // source port mentioned. (Prefix range is matched first.) Note that
- // backends_[0]->port() will never be a match for the source port because it
- // is already being used by a backend.
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* source_prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- source_prefix_range->mutable_prefix_len()->set_value(4);
- source_prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- source_prefix_range->mutable_prefix_len()->set_value(16);
- filter_chain->mutable_filter_chain_match()->add_source_ports(
- backends_[0]->port());
- // Add filter chain with two source prefix ranges (length 8 and 24). Since
- // 24 is the highest match, it should be chosen.
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- source_prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- source_prefix_range->mutable_prefix_len()->set_value(8);
- source_prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- source_prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- source_prefix_range->mutable_prefix_len()->set_value(24);
- // Add another filter chain with a non-matching source prefix range (with
- // length 30) and bad source port
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- source_prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- source_prefix_range->set_address_prefix("192.168.1.1");
- source_prefix_range->mutable_prefix_len()->set_value(30);
- filter_chain->mutable_filter_chain_match()->add_source_ports(
- backends_[0]->port());
- // Add another filter chain with no source prefix range mentioned and bad
- // source port
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_source_ports(
- backends_[0]->port());
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // A successful RPC proves that the filter chain with the longest matching
- // source prefix range was the best match.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest,
- FilterChainsWithMoreSpecificSourcePortArePreferred) {
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- // Since we don't know which port will be used by the channel, just add all
- // ports except for 0.
- for (int i = 1; i < 65536; i++) {
- filter_chain->mutable_filter_chain_match()->add_source_ports(i);
- }
- // Add another filter chain with no source port mentioned with a bad
- // DownstreamTlsContext configuration.
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- listener.clear_default_filter_chain();
- balancer_->ads_service()->SetLdsResource(
- PopulateServerListenerNameAndPort(listener, backends_[0]->port()));
- backends_[0]->Start();
- // A successful RPC proves that the filter chain with matching source port
- // was chosen.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- // Add a duplicate filter chain
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "Duplicate matching rules detected when adding filter chain: {}"));
- }
- TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnPrefixRangesNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with prefix range
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(16);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(24);
- // Add a filter chain with a duplicate prefix range entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(16);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(32);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- if (ipv6_only_) {
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "Duplicate matching rules detected when adding filter chain: "
- "{prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
- "{address_prefix=[::]:0, prefix_len=32}}}"));
- } else {
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "Duplicate matching rules detected when adding filter chain: "
- "{prefix_ranges={{address_prefix=127.0.0.0:0, prefix_len=16}, "
- "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
- }
- }
- TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnTransportProtocolNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with "raw_buffer" transport protocol
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_transport_protocol(
- "raw_buffer");
- // Add a duplicate filter chain with the same "raw_buffer" transport
- // protocol entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_transport_protocol(
- "raw_buffer");
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Duplicate matching rules detected when adding "
- "filter chain: {transport_protocol=raw_buffer}"));
- }
- TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnLocalSourceTypeNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with the local source type
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::SAME_IP_OR_LOOPBACK);
- // Add a duplicate filter chain with the same local source type entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::SAME_IP_OR_LOOPBACK);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Duplicate matching rules detected when adding "
- "filter chain: {source_type=SAME_IP_OR_LOOPBACK}"));
- }
- TEST_P(XdsServerFilterChainMatchTest,
- DuplicateMatchOnExternalSourceTypeNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with the external source type
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::EXTERNAL);
- // Add a duplicate filter chain with the same external source type entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::EXTERNAL);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Duplicate matching rules detected when adding "
- "filter chain: {source_type=EXTERNAL}"));
- }
- TEST_P(XdsServerFilterChainMatchTest,
- DuplicateMatchOnSourcePrefixRangesNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with source prefix range
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- auto* prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(16);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(24);
- // Add a filter chain with a duplicate source prefix range entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(16);
- prefix_range =
- filter_chain->mutable_filter_chain_match()->add_source_prefix_ranges();
- prefix_range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- prefix_range->mutable_prefix_len()->set_value(32);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- if (ipv6_only_) {
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "Duplicate matching rules detected when adding filter chain: "
- "{source_prefix_ranges={{address_prefix=[::]:0, prefix_len=16}, "
- "{address_prefix=[::]:0, prefix_len=32}}}"));
- } else {
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr(
- "Duplicate matching rules detected when adding filter chain: "
- "{source_prefix_ranges={{address_prefix=127.0.0.0:0, "
- "prefix_len=16}, "
- "{address_prefix=127.0.0.1:0, prefix_len=32}}}"));
- }
- }
- TEST_P(XdsServerFilterChainMatchTest, DuplicateMatchOnSourcePortNacked) {
- Listener listener = default_server_listener_;
- // Add filter chain with the external source type
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_source_ports(8080);
- // Add a duplicate filter chain with the same source port entry
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- ServerHcmAccessor().Unpack(listener));
- filter_chain->mutable_filter_chain_match()->add_source_ports(8080);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(
- response_state->error_message,
- ::testing::HasSubstr("Duplicate matching rules detected when adding "
- "filter chain: {source_ports={8080}}"));
- }
- class XdsServerRdsTest : public XdsEnabledServerStatusNotificationTest {
- protected:
- static void SetUpTestSuite() {
- gpr_setenv("GRPC_XDS_EXPERIMENTAL_RBAC", "true");
- }
- static void TearDownTestSuite() {
- gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_RBAC");
- }
- };
- TEST_P(XdsServerRdsTest, Basic) {
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerRdsTest, NacksInvalidDomainPattern) {
- RouteConfiguration route_config = default_server_route_config_;
- route_config.mutable_virtual_hosts()->at(0).add_domains("");
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backends_[0]->port(),
- route_config);
- backends_[0]->Start();
- const auto response_state = WaitForRouteConfigNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Invalid domain pattern \"\""));
- }
- TEST_P(XdsServerRdsTest, NacksEmptyDomainsList) {
- RouteConfiguration route_config = default_server_route_config_;
- route_config.mutable_virtual_hosts()->at(0).clear_domains();
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backends_[0]->port(),
- route_config);
- backends_[0]->Start();
- const auto response_state = WaitForRouteConfigNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("VirtualHost has no domains"));
- }
- TEST_P(XdsServerRdsTest, NacksEmptyRoutesList) {
- RouteConfiguration route_config = default_server_route_config_;
- route_config.mutable_virtual_hosts()->at(0).clear_routes();
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backends_[0]->port(),
- route_config);
- backends_[0]->Start();
- const auto response_state = WaitForRouteConfigNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("No route found in the virtual host"));
- }
- TEST_P(XdsServerRdsTest, NacksEmptyMatch) {
- RouteConfiguration route_config = default_server_route_config_;
- route_config.mutable_virtual_hosts()
- ->at(0)
- .mutable_routes()
- ->at(0)
- .clear_match();
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backends_[0]->port(),
- route_config);
- backends_[0]->Start();
- const auto response_state = WaitForRouteConfigNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("Match can't be null"));
- }
- TEST_P(XdsServerRdsTest, FailsRouteMatchesOtherThanNonForwardingAction) {
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), default_server_listener_, backends_[0]->port(),
- default_route_config_ /* inappropriate route config for servers */);
- backends_[0]->Start();
- // The server should be ready to serve but RPCs should fail.
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- // Test that non-inline route configuration also works for non-default filter
- // chains
- TEST_P(XdsServerRdsTest, NonInlineRouteConfigurationNonDefaultFilterChain) {
- if (!GetParam().enable_rds_testing()) {
- return;
- }
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.add_filter_chains();
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(kDefaultServerRouteConfigurationName);
- rds->mutable_config_source()->mutable_self();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsServerRdsTest, NonInlineRouteConfigurationNotAvailable) {
- if (!GetParam().enable_rds_testing()) {
- return;
- }
- Listener listener = default_server_listener_;
- PopulateServerListenerNameAndPort(listener, backends_[0]->port());
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name("unknown_server_route_config");
- rds->mutable_config_source()->mutable_self();
- listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- true /* test_expects_failure */);
- }
- // TODO(yashykt): Once https://github.com/grpc/grpc/issues/24035 is fixed, we
- // should add tests that make sure that different route configs are used for
- // incoming connections with a different match.
- TEST_P(XdsServerRdsTest, MultipleRouteConfigurations) {
- Listener listener = default_server_listener_;
- // Set a filter chain with a new route config name
- auto new_route_config = default_server_route_config_;
- new_route_config.set_name("new_server_route_config");
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name(new_route_config.name());
- rds->mutable_config_source()->mutable_self();
- listener.add_filter_chains()->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- // Set another filter chain with another route config name
- auto another_route_config = default_server_route_config_;
- another_route_config.set_name("another_server_route_config");
- http_connection_manager.mutable_rds()->set_route_config_name(
- another_route_config.name());
- auto* filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::SAME_IP_OR_LOOPBACK);
- // Add another filter chain with the same route config name
- filter_chain = listener.add_filter_chains();
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- filter_chain->mutable_filter_chain_match()->set_source_type(
- FilterChainMatch::EXTERNAL);
- // Add another filter chain with an inline route config
- filter_chain = listener.add_filter_chains();
- filter_chain->mutable_filter_chain_match()->add_source_ports(1234);
- http_connection_manager = ServerHcmAccessor().Unpack(listener);
- *http_connection_manager.mutable_route_config() =
- default_server_route_config_;
- filter_chain->add_filters()->mutable_typed_config()->PackFrom(
- http_connection_manager);
- // Set resources on the ADS service
- balancer_->ads_service()->SetRdsResource(new_route_config);
- balancer_->ads_service()->SetRdsResource(another_route_config);
- SetServerListenerNameAndRouteConfiguration(balancer_.get(), listener,
- backends_[0]->port(),
- default_server_route_config_);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- // Tests RBAC configurations on the server with RDS testing and route config
- // override permutations.
- class XdsRbacTest : public XdsServerRdsTest {
- protected:
- void SetServerRbacPolicies(Listener listener,
- const std::vector<RBAC>& rbac_policies) {
- HttpConnectionManager http_connection_manager =
- ServerHcmAccessor().Unpack(listener);
- http_connection_manager.clear_http_filters();
- RouteConfiguration route_config = default_server_route_config_;
- int count = 0;
- for (auto& rbac : rbac_policies) {
- auto* filter = http_connection_manager.add_http_filters();
- std::string filter_name = absl::StrFormat("rbac%d", ++count);
- filter->set_name(filter_name);
- switch (GetParam().filter_config_setup()) {
- case TestType::FilterConfigSetup::kHTTPConnectionManagerOriginal:
- filter->mutable_typed_config()->PackFrom(rbac);
- break;
- case TestType::FilterConfigSetup::kRouteOverride:
- filter->mutable_typed_config()->PackFrom(RBAC());
- google::protobuf::Any filter_config;
- RBACPerRoute rbac_per_route;
- *rbac_per_route.mutable_rbac() = rbac;
- filter_config.PackFrom(rbac_per_route);
- auto* config_map = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*config_map)[filter_name] = std::move(filter_config);
- }
- }
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("router");
- filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), listener, backends_[0]->port(), route_config);
- }
- void SetServerRbacPolicy(Listener listener, const RBAC& rbac) {
- SetServerRbacPolicies(std::move(listener), {rbac});
- }
- void SetServerRbacPolicy(const RBAC& rbac) {
- SetServerRbacPolicy(default_server_listener_, rbac);
- }
- };
- TEST_P(XdsRbacTest, AbsentRbacPolicy) {
- SetServerRbacPolicy(RBAC());
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // An absent RBAC policy leads to all RPCs being accepted.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- TEST_P(XdsRbacTest, LogAction) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(envoy::config::rbac::v3::RBAC_Action_LOG);
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // A Log action is identical to no rbac policy being configured.
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- using XdsRbacNackTest = XdsRbacTest;
- TEST_P(XdsRbacNackTest, NacksSchemePrincipalHeader) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
- Policy policy;
- auto* header = policy.add_principals()->mutable_header();
- header->set_name(":scheme");
- header->set_exact_match("http");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- if (GetParam().enable_rds_testing() &&
- GetParam().filter_config_setup() ==
- TestType::FilterConfigSetup::kRouteOverride) {
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("':scheme' not allowed in header"));
- } else {
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("':scheme' not allowed in header"));
- }
- }
- TEST_P(XdsRbacNackTest, NacksGrpcPrefixedPrincipalHeaders) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
- Policy policy;
- auto* header = policy.add_principals()->mutable_header();
- header->set_name("grpc-status");
- header->set_exact_match("0");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- if (GetParam().enable_rds_testing() &&
- GetParam().filter_config_setup() ==
- TestType::FilterConfigSetup::kRouteOverride) {
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
- } else {
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
- }
- }
- TEST_P(XdsRbacNackTest, NacksSchemePermissionHeader) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
- Policy policy;
- auto* header = policy.add_permissions()->mutable_header();
- header->set_name(":scheme");
- header->set_exact_match("http");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- if (GetParam().enable_rds_testing() &&
- GetParam().filter_config_setup() ==
- TestType::FilterConfigSetup::kRouteOverride) {
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("':scheme' not allowed in header"));
- } else {
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("':scheme' not allowed in header"));
- }
- }
- TEST_P(XdsRbacNackTest, NacksGrpcPrefixedPermissionHeaders) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(envoy::config::rbac::v3::RBAC_Action_ALLOW);
- Policy policy;
- auto* header = policy.add_permissions()->mutable_header();
- header->set_name("grpc-status");
- header->set_exact_match("0");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- if (GetParam().enable_rds_testing() &&
- GetParam().filter_config_setup() ==
- TestType::FilterConfigSetup::kRouteOverride) {
- const auto response_state = WaitForRdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
- } else {
- const auto response_state = WaitForLdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("'grpc-' prefixes not allowed in header"));
- }
- }
- // Tests RBAC policies where a route override is always present. Action
- // permutations are not added.
- using XdsRbacTestWithRouteOverrideAlwaysPresent = XdsRbacTest;
- TEST_P(XdsRbacTestWithRouteOverrideAlwaysPresent, EmptyRBACPerRouteOverride) {
- HttpConnectionManager http_connection_manager;
- Listener listener = default_server_listener_;
- RouteConfiguration route_config = default_server_route_config_;
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("rbac");
- // Create a top-level RBAC policy with a DENY action for all RPCs
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(RBAC_Action_DENY);
- Policy policy;
- policy.add_permissions()->set_any(true);
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- filter->mutable_typed_config()->PackFrom(rbac);
- // Override with an Empty RBACPerRoute policy which should result in RBAC
- // being disabled and RPCs being allowed.
- google::protobuf::Any filter_config;
- filter_config.PackFrom(RBACPerRoute());
- auto* config_map = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*config_map)["rbac"] = std::move(filter_config);
- filter = http_connection_manager.add_http_filters();
- filter->set_name("router");
- filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), listener, backends_[0]->port(), route_config);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- // Test a non-empty top level RBAC with a non-empty RBACPerRouteOverride
- TEST_P(XdsRbacTestWithRouteOverrideAlwaysPresent,
- NonEmptyTopLevelRBACNonEmptyPerRouteOverride) {
- HttpConnectionManager http_connection_manager;
- Listener listener = default_server_listener_;
- RouteConfiguration route_config = default_server_route_config_;
- auto* filter = http_connection_manager.add_http_filters();
- filter->set_name("rbac");
- // Create a top-level RBAC policy with a DENY action for all RPCs
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(RBAC_Action_DENY);
- Policy policy;
- policy.add_permissions()->set_any(true);
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- filter->mutable_typed_config()->PackFrom(rbac);
- // Override with a non-empty RBACPerRoute policy which allows all RPCs.
- google::protobuf::Any filter_config;
- RBACPerRoute rbac_per_route;
- rules = rbac_per_route.mutable_rbac()->mutable_rules();
- rules->set_action(RBAC_Action_ALLOW);
- (*rules->mutable_policies())["policy"] = policy;
- filter_config.PackFrom(RBACPerRoute());
- auto* config_map = route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*config_map)["rbac"] = std::move(filter_config);
- filter = http_connection_manager.add_http_filters();
- filter->set_name("router");
- filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- ServerHcmAccessor().Pack(http_connection_manager, &listener);
- SetServerListenerNameAndRouteConfiguration(
- balancer_.get(), listener, backends_[0]->port(), route_config);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {});
- }
- // Adds Action Permutations to XdsRbacTest
- using XdsRbacTestWithActionPermutations = XdsRbacTest;
- TEST_P(XdsRbacTestWithActionPermutations, EmptyRbacPolicy) {
- RBAC rbac;
- rbac.mutable_rules()->set_action(GetParam().rbac_action());
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // An empty RBAC policy leads to all RPCs being rejected.
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_permissions()->set_any(true);
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, MultipleRbacPolicies) {
- RBAC always_allow;
- auto* rules = always_allow.mutable_rules();
- rules->set_action(RBAC_Action_ALLOW);
- Policy policy;
- policy.add_permissions()->set_any(true);
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- RBAC rbac;
- rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicies(default_server_listener_,
- {always_allow, rbac, always_allow});
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, MethodPostPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_permissions()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("POST");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // All RPCs use POST method by default
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test an RPC with a different method type
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_cacheable(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_EQ(status.error_code(), GetParam().rbac_action() == RBAC_Action_DENY
- ? grpc::StatusCode::OK
- : grpc::StatusCode::PERMISSION_DENIED)
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- }
- TEST_P(XdsRbacTestWithActionPermutations, MethodGetPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_permissions()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("GET");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // Send a cacheable RPC so that GET method is used
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_cacheable(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_EQ(status.error_code(), GetParam().rbac_action() == RBAC_Action_ALLOW
- ? grpc::StatusCode::OK
- : grpc::StatusCode::PERMISSION_DENIED)
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- // Test an RPC with a different method type
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, MethodPutPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_permissions()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("PUT");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // Send an idempotent RPC so that PUT method is used
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_idempotent(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_EQ(status.error_code(), GetParam().rbac_action() == RBAC_Action_ALLOW
- ? grpc::StatusCode::OK
- : grpc::StatusCode::PERMISSION_DENIED)
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- // Test an RPC with a different method type
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, UrlPathPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_permissions()->mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test an RPC with a different URL path
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo1(&context, request, &response);
- EXPECT_TRUE(GetParam().rbac_action() == RBAC_Action_DENY ? status.ok()
- : !status.ok())
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- }
- TEST_P(XdsRbacTestWithActionPermutations, DestinationIpPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* range = policy.add_permissions()->mutable_destination_ip();
- range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_permissions();
- range = policy.add_permissions()->mutable_destination_ip();
- range->set_address_prefix(ipv6_only_ ? "::2" : "127.0.0.2");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations,
- DestinationPortPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_permissions()->set_destination_port(backends_[0]->port());
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_permissions();
- policy.add_permissions()->set_destination_port(1);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, MetadataPermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_permissions()->mutable_metadata();
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test metadata with inverted match
- policy.clear_permissions();
- policy.add_permissions()->mutable_metadata()->set_invert(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, ReqServerNamePermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_principals()->set_any(true);
- policy.add_permissions()->mutable_requested_server_name()->set_exact(
- "server_name");
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- policy.clear_permissions();
- policy.add_permissions()->mutable_requested_server_name()->set_exact("");
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, NotRulePermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_permissions()
- ->mutable_not_rule()
- ->mutable_requested_server_name()
- ->set_exact("server_name");
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_permissions();
- policy.add_permissions()->mutable_not_rule()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AndRulePermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* and_rules = policy.add_permissions()->mutable_and_rules();
- and_rules->add_rules()->set_any(true);
- and_rules->add_rules()->set_destination_port(backends_[0]->port());
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- and_rules = (*policy.mutable_permissions())[0].mutable_and_rules();
- (*and_rules->mutable_rules())[1].set_destination_port(1);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, OrRulePermissionAnyPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* or_rules = policy.add_permissions()->mutable_or_rules();
- or_rules->add_rules()->mutable_not_rule()->set_any(true);
- or_rules->add_rules()->set_destination_port(backends_[0]->port());
- policy.add_principals()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- or_rules = (*policy.mutable_permissions())[0].mutable_or_rules();
- (*or_rules->mutable_rules())[1].set_destination_port(1);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionMethodPostPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_principals()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("POST");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // All RPCs use POST method by default
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test an RPC with a different method type
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_cacheable(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_EQ(status.error_code(), GetParam().rbac_action() == RBAC_Action_DENY
- ? grpc::StatusCode::OK
- : grpc::StatusCode::PERMISSION_DENIED)
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionMethodGetPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_principals()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("GET");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // Send a cacheable RPC so that GET method is used
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_cacheable(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_TRUE(GetParam().rbac_action() == RBAC_Action_ALLOW ? status.ok()
- : !status.ok())
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- // Test an RPC with a different method type
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionMethodPutPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* header = policy.add_principals()->mutable_header();
- header->set_name(":method");
- header->set_exact_match("PUT");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- // Send an idempotent RPC so that PUT method is used
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- context.set_idempotent(true);
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo(&context, request, &response);
- EXPECT_TRUE(GetParam().rbac_action() == RBAC_Action_ALLOW ? status.ok()
- : !status.ok())
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- // Test an RPC with a different method type
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionUrlPathPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_principals()->mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test an RPC with a different URL path
- auto stub = grpc::testing::EchoTestService::NewStub(CreateInsecureChannel());
- ClientContext context;
- context.set_wait_for_ready(true);
- context.set_deadline(grpc_timeout_milliseconds_to_deadline(2000));
- EchoRequest request;
- request.set_message(kRequestMessage);
- EchoResponse response;
- Status status = stub->Echo1(&context, request, &response);
- EXPECT_TRUE(GetParam().rbac_action() == RBAC_Action_DENY ? status.ok()
- : !status.ok())
- << status.error_code() << ", " << status.error_message() << ", "
- << status.error_details() << ", " << context.debug_error_string();
- }
- TEST_P(XdsRbacTestWithActionPermutations,
- AnyPermissionDirectRemoteIpPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* range = policy.add_principals()->mutable_direct_remote_ip();
- range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_principals();
- range = policy.add_principals()->mutable_direct_remote_ip();
- range->set_address_prefix(ipv6_only_ ? "::2" : "127.0.0.2");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionRemoteIpPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* range = policy.add_principals()->mutable_remote_ip();
- range->set_address_prefix(ipv6_only_ ? "::1" : "127.0.0.1");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_principals();
- range = policy.add_principals()->mutable_remote_ip();
- range->set_address_prefix(ipv6_only_ ? "::2" : "127.0.0.2");
- range->mutable_prefix_len()->set_value(ipv6_only_ ? 128 : 32);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionAuthenticatedPrincipal) {
- FakeCertificateProvider::CertDataMap fake1_cert_map = {
- {"", {root_cert_, identity_pair_}}};
- g_fake1_cert_data_map = &fake1_cert_map;
- Listener listener = default_server_listener_;
- auto* filter_chain = listener.mutable_default_filter_chain();
- auto* transport_socket = filter_chain->mutable_transport_socket();
- transport_socket->set_name("envoy.transport_sockets.tls");
- DownstreamTlsContext downstream_tls_context;
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_tls_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.mutable_common_tls_context()
- ->mutable_validation_context()
- ->mutable_ca_certificate_provider_instance()
- ->set_instance_name("fake_plugin1");
- downstream_tls_context.mutable_require_client_certificate()->set_value(true);
- transport_socket->mutable_typed_config()->PackFrom(downstream_tls_context);
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_principals()
- ->mutable_authenticated()
- ->mutable_principal_name()
- ->set_exact("*.test.google.fr");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(listener, rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateMtlsChannel(); },
- server_authenticated_identity_, client_authenticated_identity_,
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionMetadataPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_principals()->mutable_metadata();
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- // Test metadata with inverted match
- policy.clear_principals();
- policy.add_principals()->mutable_metadata()->set_invert(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionNotIdPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- policy.add_principals()
- ->mutable_not_id()
- ->mutable_url_path()
- ->mutable_path()
- ->set_exact("/grpc.testing.EchoTestService/Echo1");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- policy.clear_principals();
- policy.add_principals()->mutable_not_id()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionAndIdPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* and_ids = policy.add_principals()->mutable_and_ids();
- and_ids->add_ids()->set_any(true);
- and_ids->add_ids()->mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- and_ids = (*policy.mutable_principals())[0].mutable_and_ids();
- (*and_ids->mutable_ids())[1].mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo1");
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- TEST_P(XdsRbacTestWithActionPermutations, AnyPermissionOrIdPrincipal) {
- RBAC rbac;
- auto* rules = rbac.mutable_rules();
- rules->set_action(GetParam().rbac_action());
- Policy policy;
- auto* or_ids = policy.add_principals()->mutable_or_ids();
- or_ids->add_ids()->mutable_not_id()->set_any(true);
- or_ids->add_ids()->mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo");
- policy.add_permissions()->set_any(true);
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- backends_[0]->Start();
- backends_[0]->notifier()->WaitOnServingStatusChange(
- absl::StrCat(ipv6_only_ ? "[::1]:" : "127.0.0.1:", backends_[0]->port()),
- grpc::StatusCode::OK);
- SendRpc([this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_DENY,
- grpc::StatusCode::PERMISSION_DENIED);
- // Change the policy itself for a negative test where there is no match.
- or_ids = (*policy.mutable_principals())[0].mutable_or_ids();
- (*or_ids->mutable_ids())[1].mutable_url_path()->mutable_path()->set_exact(
- "/grpc.testing.EchoTestService/Echo1");
- (*rules->mutable_policies())["policy"] = policy;
- SetServerRbacPolicy(rbac);
- SendRpc(
- [this]() { return CreateInsecureChannel(); }, {}, {},
- /*test_expects_failure=*/GetParam().rbac_action() == RBAC_Action_ALLOW,
- grpc::StatusCode::PERMISSION_DENIED);
- }
- using EdsTest = BasicTest;
- // Tests that EDS client should send a NACK if the EDS update contains
- // sparse priorities.
- TEST_P(EdsTest, NacksSparsePriorityList) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(), kDefaultLocalityWeight, 1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- const auto response_state = WaitForEdsNack();
- ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
- EXPECT_THAT(response_state->error_message,
- ::testing::HasSubstr("sparse priority list"));
- }
- // In most of our tests, we use different names for different resource
- // types, to make sure that there are no cut-and-paste errors in the code
- // that cause us to look at data for the wrong resource type. So we add
- // this test to make sure that the EDS resource name defaults to the
- // cluster name if not specified in the CDS resource.
- TEST_P(EdsTest, EdsServiceNameDefaultsToClusterName) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args, kDefaultClusterName));
- Cluster cluster = default_cluster_;
- cluster.mutable_eds_cluster_config()->clear_service_name();
- balancer_->ads_service()->SetCdsResource(cluster);
- CheckRpcSendOk();
- }
- class TimeoutTest : public XdsEnd2endTest {
- protected:
- TimeoutTest()
- : XdsEnd2endTest(/*num_backends=*/4,
- /*client_load_reporting_interval_seconds=*/100,
- /*xds_resource_does_not_exist_timeout_ms=*/500,
- /*use_xds_enabled_server=*/false) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- };
- TEST_P(TimeoutTest, LdsServerIgnoresRequest) {
- balancer_->ads_service()->IgnoreResourceType(kLdsTypeUrl);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, LdsResourceNotPresentInRequest) {
- balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, LdsSecondResourceNotPresentInRequest) {
- ASSERT_NE(GetParam().bootstrap_source(), TestType::kBootstrapFromChannelArg)
- << "This test cannot use bootstrap from channel args, because it "
- "needs two channels to use the same XdsClient instance.";
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- // Create second channel for a new server name.
- // This should fail because there is no LDS resource for this server name.
- auto channel2 =
- CreateChannel(/*failover_timeout=*/0, "new-server.example.com");
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- ClientContext context;
- EchoRequest request;
- EchoResponse response;
- RpcOptions rpc_options;
- rpc_options.SetupRpc(&context, &request);
- auto status =
- SendRpcMethod(stub2.get(), rpc_options, &context, request, &response);
- EXPECT_EQ(StatusCode::UNAVAILABLE, status.error_code());
- }
- TEST_P(TimeoutTest, RdsServerIgnoresRequest) {
- balancer_->ads_service()->IgnoreResourceType(kRdsTypeUrl);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, RdsResourceNotPresentInRequest) {
- balancer_->ads_service()->UnsetResource(kRdsTypeUrl,
- kDefaultRouteConfigurationName);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, RdsSecondResourceNotPresentInRequest) {
- ASSERT_NE(GetParam().bootstrap_source(), TestType::kBootstrapFromChannelArg)
- << "This test cannot use bootstrap from channel args, because it "
- "needs two channels to use the same XdsClient instance.";
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Add listener for 2nd channel, but no RDS resource.
- const char* kNewServerName = "new-server.example.com";
- Listener listener = default_listener_;
- listener.set_name(kNewServerName);
- HttpConnectionManager http_connection_manager =
- ClientHcmAccessor().Unpack(listener);
- auto* rds = http_connection_manager.mutable_rds();
- rds->set_route_config_name("rds_resource_does_not_exist");
- rds->mutable_config_source()->mutable_self();
- ClientHcmAccessor().Pack(http_connection_manager, &listener);
- balancer_->ads_service()->SetLdsResource(listener);
- WaitForAllBackends();
- // Create second channel for a new server name.
- // This should fail because the LDS resource points to a non-existent RDS
- // resource.
- auto channel2 = CreateChannel(/*failover_timeout=*/0, kNewServerName);
- auto stub2 = grpc::testing::EchoTestService::NewStub(channel2);
- ClientContext context;
- EchoRequest request;
- EchoResponse response;
- RpcOptions rpc_options;
- rpc_options.SetupRpc(&context, &request);
- auto status =
- SendRpcMethod(stub2.get(), rpc_options, &context, request, &response);
- EXPECT_EQ(StatusCode::UNAVAILABLE, status.error_code());
- }
- TEST_P(TimeoutTest, CdsServerIgnoresRequest) {
- balancer_->ads_service()->IgnoreResourceType(kCdsTypeUrl);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, CdsResourceNotPresentInRequest) {
- balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, CdsSecondResourceNotPresentInRequest) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- // Change route config to point to non-existing cluster.
- const char* kNewClusterName = "new_cluster_name";
- RouteConfiguration route_config = default_route_config_;
- route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- balancer_->ads_service()->SetRdsResource(route_config);
- // New cluster times out.
- // May need to wait a bit for the change to propagate to the client.
- gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
- bool error_seen = false;
- do {
- auto status = SendRpc();
- if (status.error_code() == StatusCode::UNAVAILABLE) {
- error_seen = true;
- break;
- }
- } while (gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
- EXPECT_TRUE(error_seen);
- }
- TEST_P(TimeoutTest, EdsServerIgnoresRequest) {
- balancer_->ads_service()->IgnoreResourceType(kEdsTypeUrl);
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, EdsResourceNotPresentInRequest) {
- // No need to remove EDS resource, since the test suite does not add it
- // by default.
- CheckRpcSendFailure();
- }
- TEST_P(TimeoutTest, EdsSecondResourceNotPresentInRequest) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- // New cluster that points to a non-existant EDS resource.
- const char* kNewClusterName = "new_cluster_name";
- Cluster cluster = default_cluster_;
- cluster.set_name(kNewClusterName);
- cluster.mutable_eds_cluster_config()->set_service_name(
- "eds_service_name_does_not_exist");
- balancer_->ads_service()->SetCdsResource(cluster);
- // Now add a route pointing to the new cluster.
- RouteConfiguration route_config = default_route_config_;
- auto* route = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
- *route_config.mutable_virtual_hosts(0)->add_routes() = *route;
- route->mutable_match()->set_path("/grpc.testing.EchoTestService/Echo1");
- route->mutable_route()->set_cluster(kNewClusterName);
- balancer_->ads_service()->SetRdsResource(route_config);
- // New EDS resource times out.
- // May need to wait a bit for the RDS change to propagate to the client.
- gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10);
- bool error_seen = false;
- do {
- auto status = SendRpc(RpcOptions().set_rpc_method(METHOD_ECHO1));
- if (status.error_code() == StatusCode::UNAVAILABLE) {
- error_seen = true;
- break;
- }
- } while (gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
- EXPECT_TRUE(error_seen);
- }
- using LocalityMapTest = BasicTest;
- // Tests that the localities in a locality map are picked according to their
- // weights.
- TEST_P(LocalityMapTest, WeightedRoundRobin) {
- const int kLocalityWeight0 = 2;
- const int kLocalityWeight1 = 8;
- const int kTotalLocalityWeight = kLocalityWeight0 + kLocalityWeight1;
- const double kLocalityWeightRate0 =
- static_cast<double>(kLocalityWeight0) / kTotalLocalityWeight;
- const double kLocalityWeightRate1 =
- static_cast<double>(kLocalityWeight1) / kTotalLocalityWeight;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kLocalityWeightRate0, kErrorTolerance);
- // ADS response contains 2 localities, each of which contains 1 backend.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kLocalityWeight0},
- {"locality1", CreateEndpointsForBackends(1, 2), kLocalityWeight1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for both backends to be ready.
- WaitForAllBackends(0, 2);
- // Send kNumRpcs RPCs.
- CheckRpcSendOk(kNumRpcs);
- // The locality picking rates should be roughly equal to the expectation.
- const double locality_picked_rate_0 =
- static_cast<double>(backends_[0]->backend_service()->request_count()) /
- kNumRpcs;
- const double locality_picked_rate_1 =
- static_cast<double>(backends_[1]->backend_service()->request_count()) /
- kNumRpcs;
- EXPECT_THAT(locality_picked_rate_0,
- ::testing::DoubleNear(kLocalityWeightRate0, kErrorTolerance));
- EXPECT_THAT(locality_picked_rate_1,
- ::testing::DoubleNear(kLocalityWeightRate1, kErrorTolerance));
- }
- // Tests that we correctly handle a locality containing no endpoints.
- TEST_P(LocalityMapTest, LocalityContainingNoEndpoints) {
- const size_t kNumRpcs = 5000;
- // EDS response contains 2 localities, one with no endpoints.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- {"locality1", {}},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for both backends to be ready.
- WaitForAllBackends();
- // Send kNumRpcs RPCs.
- CheckRpcSendOk(kNumRpcs);
- // All traffic should go to the reachable locality.
- EXPECT_EQ(backends_[0]->backend_service()->request_count(),
- kNumRpcs / backends_.size());
- EXPECT_EQ(backends_[1]->backend_service()->request_count(),
- kNumRpcs / backends_.size());
- EXPECT_EQ(backends_[2]->backend_service()->request_count(),
- kNumRpcs / backends_.size());
- EXPECT_EQ(backends_[3]->backend_service()->request_count(),
- kNumRpcs / backends_.size());
- }
- // EDS update with no localities.
- TEST_P(LocalityMapTest, NoLocalities) {
- balancer_->ads_service()->SetEdsResource(BuildEdsResource({}));
- Status status = SendRpc();
- EXPECT_FALSE(status.ok());
- EXPECT_EQ(status.error_code(), StatusCode::UNAVAILABLE);
- }
- // Tests that the locality map can work properly even when it contains a large
- // number of localities.
- TEST_P(LocalityMapTest, StressTest) {
- const size_t kNumLocalities = 100;
- const uint32_t kRpcTimeoutMs = 5000;
- // The first ADS response contains kNumLocalities localities, each of which
- // contains backend 0.
- EdsResourceArgs args;
- for (size_t i = 0; i < kNumLocalities; ++i) {
- std::string name = absl::StrCat("locality", i);
- EdsResourceArgs::Locality locality(name, CreateEndpointsForBackends(0, 1));
- args.locality_list.emplace_back(std::move(locality));
- }
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until backend 0 is ready, before which kNumLocalities localities are
- // received and handled by the xds policy.
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false),
- RpcOptions().set_timeout_ms(kRpcTimeoutMs));
- EXPECT_EQ(0U, backends_[1]->backend_service()->request_count());
- // The second ADS response contains 1 locality, which contains backend 1.
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(1, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until backend 1 is ready, before which kNumLocalities localities are
- // removed by the xds policy.
- WaitForBackend(1);
- }
- // Tests that the localities in a locality map are picked correctly after
- // update (addition, modification, deletion).
- TEST_P(LocalityMapTest, UpdateMap) {
- const size_t kNumRpcs = 3000;
- // The locality weight for the first 3 localities.
- const std::vector<int> kLocalityWeights0 = {2, 3, 4};
- const double kTotalLocalityWeight0 =
- std::accumulate(kLocalityWeights0.begin(), kLocalityWeights0.end(), 0);
- std::vector<double> locality_weight_rate_0;
- locality_weight_rate_0.reserve(kLocalityWeights0.size());
- for (int weight : kLocalityWeights0) {
- locality_weight_rate_0.push_back(weight / kTotalLocalityWeight0);
- }
- // Delete the first locality, keep the second locality, change the third
- // locality's weight from 4 to 2, and add a new locality with weight 6.
- const std::vector<int> kLocalityWeights1 = {3, 2, 6};
- const double kTotalLocalityWeight1 =
- std::accumulate(kLocalityWeights1.begin(), kLocalityWeights1.end(), 0);
- std::vector<double> locality_weight_rate_1 = {
- 0 /* placeholder for locality 0 */};
- for (int weight : kLocalityWeights1) {
- locality_weight_rate_1.push_back(weight / kTotalLocalityWeight1);
- }
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), 2},
- {"locality1", CreateEndpointsForBackends(1, 2), 3},
- {"locality2", CreateEndpointsForBackends(2, 3), 4},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for the first 3 backends to be ready.
- WaitForAllBackends(0, 3);
- gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
- // Send kNumRpcs RPCs.
- CheckRpcSendOk(kNumRpcs);
- gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
- // The picking rates of the first 3 backends should be roughly equal to the
- // expectation.
- std::vector<double> locality_picked_rates;
- for (size_t i = 0; i < 3; ++i) {
- locality_picked_rates.push_back(
- static_cast<double>(backends_[i]->backend_service()->request_count()) /
- kNumRpcs);
- }
- const double kErrorTolerance = 0.2;
- for (size_t i = 0; i < 3; ++i) {
- gpr_log(GPR_INFO, "Locality %" PRIuPTR " rate %f", i,
- locality_picked_rates[i]);
- EXPECT_THAT(
- locality_picked_rates[i],
- ::testing::AllOf(
- ::testing::Ge(locality_weight_rate_0[i] * (1 - kErrorTolerance)),
- ::testing::Le(locality_weight_rate_0[i] * (1 + kErrorTolerance))));
- }
- args = EdsResourceArgs({
- {"locality1", CreateEndpointsForBackends(1, 2), 3},
- {"locality2", CreateEndpointsForBackends(2, 3), 2},
- {"locality3", CreateEndpointsForBackends(3, 4), 6},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Backend 3 hasn't received any request.
- EXPECT_EQ(0U, backends_[3]->backend_service()->request_count());
- // Wait until the locality update has been processed, as signaled by backend
- // 3 receiving a request.
- WaitForAllBackends(3, 4);
- gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH ==========");
- // Send kNumRpcs RPCs.
- CheckRpcSendOk(kNumRpcs);
- gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH ==========");
- // Backend 0 no longer receives any request.
- EXPECT_EQ(0U, backends_[0]->backend_service()->request_count());
- // The picking rates of the last 3 backends should be roughly equal to the
- // expectation.
- locality_picked_rates = {0 /* placeholder for backend 0 */};
- for (size_t i = 1; i < 4; ++i) {
- locality_picked_rates.push_back(
- static_cast<double>(backends_[i]->backend_service()->request_count()) /
- kNumRpcs);
- }
- for (size_t i = 1; i < 4; ++i) {
- gpr_log(GPR_INFO, "Locality %" PRIuPTR " rate %f", i,
- locality_picked_rates[i]);
- EXPECT_THAT(
- locality_picked_rates[i],
- ::testing::AllOf(
- ::testing::Ge(locality_weight_rate_1[i] * (1 - kErrorTolerance)),
- ::testing::Le(locality_weight_rate_1[i] * (1 + kErrorTolerance))));
- }
- }
- // Tests that we don't fail RPCs when replacing all of the localities in
- // a given priority.
- TEST_P(LocalityMapTest, ReplaceAllLocalitiesInPriority) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({
- {"locality1", CreateEndpointsForBackends(1, 2)},
- });
- std::thread delayed_resource_setter(
- std::bind(&BasicTest::SetEdsResourceWithDelay, this, balancer_.get(),
- BuildEdsResource(args), 5000));
- // Wait for the first backend to be ready.
- WaitForBackend(0);
- // Keep sending RPCs until we switch over to backend 1, which tells us
- // that we received the update. No RPCs should fail during this
- // transition.
- WaitForBackend(1);
- delayed_resource_setter.join();
- }
- class FailoverTest : public BasicTest {
- public:
- void SetUp() override {
- BasicTest::SetUp();
- ResetStub(500);
- }
- };
- // Localities with the highest priority are used when multiple priority exist.
- TEST_P(FailoverTest, ChooseHighestPriority) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 1},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 2},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 3},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 0},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForBackend(3, WaitForBackendOptions().set_reset_counters(false));
- for (size_t i = 0; i < 3; ++i) {
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- }
- // Does not choose priority with no endpoints.
- TEST_P(FailoverTest, DoesNotUsePriorityWithNoEndpoints) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 1},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 2},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 3},
- {"locality3", {}, kDefaultLocalityWeight, 0},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForBackend(0, WaitForBackendOptions().set_reset_counters(false));
- for (size_t i = 1; i < 3; ++i) {
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- }
- // Does not choose locality with no endpoints.
- TEST_P(FailoverTest, DoesNotUseLocalityWithNoEndpoints) {
- EdsResourceArgs args({
- {"locality0", {}, kDefaultLocalityWeight, 0},
- {"locality1", CreateEndpointsForBackends(), kDefaultLocalityWeight, 0},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for all backends to be used.
- WaitForAllBackends();
- }
- // If the higher priority localities are not reachable, failover to the
- // highest priority among the rest.
- TEST_P(FailoverTest, Failover) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 1},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 2},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 3},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 0},
- });
- ShutdownBackend(3);
- ShutdownBackend(0);
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForBackend(1, WaitForBackendOptions().set_reset_counters(false));
- for (size_t i = 0; i < 4; ++i) {
- if (i == 1) continue;
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- }
- // If a locality with higher priority than the current one becomes ready,
- // switch to it.
- TEST_P(FailoverTest, SwitchBackToHigherPriority) {
- const size_t kNumRpcs = 100;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 1},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 2},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 3},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 0},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForBackend(3);
- ShutdownBackend(3);
- ShutdownBackend(0);
- WaitForBackend(
- 1, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
- true));
- for (size_t i = 0; i < 4; ++i) {
- if (i == 1) continue;
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- StartBackend(0);
- WaitForBackend(0);
- CheckRpcSendOk(kNumRpcs);
- EXPECT_EQ(kNumRpcs, backends_[0]->backend_service()->request_count());
- }
- // The first update only contains unavailable priorities. The second update
- // contains available priorities.
- TEST_P(FailoverTest, UpdateInitialUnavailable) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 1},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 2},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 3},
- });
- ShutdownBackend(0);
- ShutdownBackend(1);
- std::thread delayed_resource_setter(
- std::bind(&BasicTest::SetEdsResourceWithDelay, this, balancer_.get(),
- BuildEdsResource(args), 1000));
- gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_millis(500, GPR_TIMESPAN));
- // Send 0.5 second worth of RPCs.
- do {
- CheckRpcSendFailure();
- } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
- WaitForBackend(
- 2, WaitForBackendOptions().set_reset_counters(false).set_allow_failures(
- true));
- for (size_t i = 0; i < 4; ++i) {
- if (i == 2) continue;
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- delayed_resource_setter.join();
- }
- // Tests that after the localities' priorities are updated, we still choose
- // the highest READY priority with the updated localities.
- TEST_P(FailoverTest, UpdatePriority) {
- const size_t kNumRpcs = 100;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 1},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 2},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 3},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 0},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 2},
- {"locality1", CreateEndpointsForBackends(1, 2), kDefaultLocalityWeight,
- 0},
- {"locality2", CreateEndpointsForBackends(2, 3), kDefaultLocalityWeight,
- 1},
- {"locality3", CreateEndpointsForBackends(3, 4), kDefaultLocalityWeight,
- 3},
- });
- std::thread delayed_resource_setter(
- std::bind(&BasicTest::SetEdsResourceWithDelay, this, balancer_.get(),
- BuildEdsResource(args), 1000));
- WaitForBackend(3, WaitForBackendOptions().set_reset_counters(false));
- for (size_t i = 0; i < 3; ++i) {
- EXPECT_EQ(0U, backends_[i]->backend_service()->request_count());
- }
- WaitForBackend(1);
- CheckRpcSendOk(kNumRpcs);
- EXPECT_EQ(kNumRpcs, backends_[1]->backend_service()->request_count());
- delayed_resource_setter.join();
- }
- // Moves all localities in the current priority to a higher priority.
- TEST_P(FailoverTest, MoveAllLocalitiesInCurrentPriorityToHigherPriority) {
- // First update:
- // - Priority 0 is locality 0, containing backend 0, which is down.
- // - Priority 1 is locality 1, containing backends 1 and 2, which are up.
- ShutdownBackend(0);
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality1", CreateEndpointsForBackends(1, 3), kDefaultLocalityWeight,
- 1},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Second update:
- // - Priority 0 contains both localities 0 and 1.
- // - Priority 1 is not present.
- // - We add backend 3 to locality 1, just so we have a way to know
- // when the update has been seen by the client.
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(0, 1), kDefaultLocalityWeight,
- 0},
- {"locality1", CreateEndpointsForBackends(1, 4), kDefaultLocalityWeight,
- 0},
- });
- std::thread delayed_resource_setter(
- std::bind(&BasicTest::SetEdsResourceWithDelay, this, balancer_.get(),
- BuildEdsResource(args), 1000));
- // When we get the first update, all backends in priority 0 are down,
- // so we will create priority 1. Backends 1 and 2 should have traffic,
- // but backend 3 should not.
- WaitForAllBackends(1, 3, WaitForBackendOptions().set_reset_counters(false));
- EXPECT_EQ(0UL, backends_[3]->backend_service()->request_count());
- // When backend 3 gets traffic, we know the second update has been seen.
- WaitForBackend(3);
- // The ADS service of balancer 0 got at least 1 response.
- EXPECT_TRUE(balancer_->ads_service()->eds_response_state().has_value());
- delayed_resource_setter.join();
- }
- using DropTest = BasicTest;
- // Tests that RPCs are dropped according to the drop config.
- TEST_P(DropTest, Vanilla) {
- const uint32_t kDropPerMillionForLb = 100000;
- const uint32_t kDropPerMillionForThrottle = 200000;
- const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
- const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
- const double kDropRateForLbAndThrottle =
- kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
- // The ADS response contains two drop categories.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
- {kThrottleDropType, kDropPerMillionForThrottle}};
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcs RPCs and count the drops.
- size_t num_drops =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, "EDS-configured drop: ");
- // The drop rate should be roughly equal to the expectation.
- const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
- EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
- kErrorTolerance));
- }
- // Tests that drop config is converted correctly from per hundred.
- TEST_P(DropTest, DropPerHundred) {
- const uint32_t kDropPerHundredForLb = 10;
- const double kDropRateForLb = kDropPerHundredForLb / 100.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
- // The ADS response contains one drop category.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- args.drop_categories = {{kLbDropType, kDropPerHundredForLb}};
- args.drop_denominator = FractionalPercent::HUNDRED;
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcs RPCs and count the drops.
- size_t num_drops =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, "EDS-configured drop: ");
- // The drop rate should be roughly equal to the expectation.
- const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
- EXPECT_THAT(seen_drop_rate,
- ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
- }
- // Tests that drop config is converted correctly from per ten thousand.
- TEST_P(DropTest, DropPerTenThousand) {
- const uint32_t kDropPerTenThousandForLb = 1000;
- const double kDropRateForLb = kDropPerTenThousandForLb / 10000.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
- // The ADS response contains one drop category.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- args.drop_categories = {{kLbDropType, kDropPerTenThousandForLb}};
- args.drop_denominator = FractionalPercent::TEN_THOUSAND;
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcs RPCs and count the drops.
- size_t num_drops =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, "EDS-configured drop: ");
- // The drop rate should be roughly equal to the expectation.
- const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
- EXPECT_THAT(seen_drop_rate,
- ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
- }
- // Tests that drop is working correctly after update.
- TEST_P(DropTest, Update) {
- const uint32_t kDropPerMillionForLb = 100000;
- const uint32_t kDropPerMillionForThrottle = 200000;
- const double kErrorTolerance = 0.05;
- const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
- const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
- const double kDropRateForLbAndThrottle =
- kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
- const size_t kNumRpcsLbOnly =
- ComputeIdealNumRpcs(kDropRateForLb, kErrorTolerance);
- const size_t kNumRpcsBoth =
- ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
- // The first ADS response contains one drop category.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- args.drop_categories = {{kLbDropType, kDropPerMillionForLb}};
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcsLbOnly RPCs and count the drops.
- gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH ==========");
- size_t num_drops = SendRpcsAndCountFailuresWithMessage(
- kNumRpcsLbOnly, "EDS-configured drop: ");
- gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH ==========");
- // The drop rate should be roughly equal to the expectation.
- double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcsLbOnly;
- gpr_log(GPR_INFO, "First batch drop rate %f", seen_drop_rate);
- EXPECT_THAT(seen_drop_rate,
- ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
- // The second ADS response contains two drop categories, send an update EDS
- // response.
- args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
- {kThrottleDropType, kDropPerMillionForThrottle}};
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until the drop rate increases to the middle of the two configs,
- // which implies that the update has been in effect.
- const double kDropRateThreshold =
- (kDropRateForLb + kDropRateForLbAndThrottle) / 2;
- size_t num_rpcs = kNumRpcsBoth;
- while (seen_drop_rate < kDropRateThreshold) {
- EchoResponse response;
- const Status status = SendRpc(RpcOptions(), &response);
- ++num_rpcs;
- if (!status.ok() &&
- absl::StartsWith(status.error_message(), "EDS-configured drop: ")) {
- ++num_drops;
- } else {
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- EXPECT_EQ(response.message(), kRequestMessage);
- }
- seen_drop_rate = static_cast<double>(num_drops) / num_rpcs;
- }
- // Send kNumRpcsBoth RPCs and count the drops.
- gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH ==========");
- num_drops = SendRpcsAndCountFailuresWithMessage(kNumRpcsBoth,
- "EDS-configured drop: ");
- gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH ==========");
- // The new drop rate should be roughly equal to the expectation.
- seen_drop_rate = static_cast<double>(num_drops) / kNumRpcsBoth;
- gpr_log(GPR_INFO, "Second batch drop rate %f", seen_drop_rate);
- EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
- kErrorTolerance));
- }
- // Tests that all the RPCs are dropped if any drop category drops 100%.
- TEST_P(DropTest, DropAll) {
- const size_t kNumRpcs = 1000;
- const uint32_t kDropPerMillionForLb = 100000;
- const uint32_t kDropPerMillionForThrottle = 1000000;
- // The ADS response contains two drop categories.
- EdsResourceArgs args;
- args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
- {kThrottleDropType, kDropPerMillionForThrottle}};
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcs RPCs and all of them are dropped.
- size_t num_drops =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, "EDS-configured drop: ");
- EXPECT_EQ(num_drops, kNumRpcs);
- }
- class ClientLoadReportingTest : public XdsEnd2endTest {
- public:
- ClientLoadReportingTest() : XdsEnd2endTest(4, 3) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- };
- // Tests that the load report received at the balancer is correct.
- TEST_P(ClientLoadReportingTest, Vanilla) {
- const size_t kNumRpcsPerAddress = 10;
- const size_t kNumFailuresPerAddress = 3;
- // TODO(juanlishen): Partition the backends after multiple localities is
- // tested.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until all backends are ready.
- size_t num_warmup_rpcs = WaitForAllBackends();
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * num_backends_);
- CheckRpcSendFailure(CheckRpcSendFailureOptions()
- .set_times(kNumFailuresPerAddress * num_backends_)
- .set_rpc_options(RpcOptions().set_server_fail(true)));
- // Check that each backend got the right number of requests.
- for (size_t i = 0; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress + kNumFailuresPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- // The load report received at the balancer should be correct.
- std::vector<ClientStats> load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(load_report.size(), 1UL);
- ClientStats& client_stats = load_report.front();
- EXPECT_EQ(kNumRpcsPerAddress * num_backends_ + num_warmup_rpcs,
- client_stats.total_successful_requests());
- EXPECT_EQ(0U, client_stats.total_requests_in_progress());
- EXPECT_EQ((kNumRpcsPerAddress + kNumFailuresPerAddress) * num_backends_ +
- num_warmup_rpcs,
- client_stats.total_issued_requests());
- EXPECT_EQ(kNumFailuresPerAddress * num_backends_,
- client_stats.total_error_requests());
- EXPECT_EQ(0U, client_stats.total_dropped_requests());
- // The LRS service got a single request, and sent a single response.
- EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
- }
- // Tests send_all_clusters.
- TEST_P(ClientLoadReportingTest, SendAllClusters) {
- balancer_->lrs_service()->set_send_all_clusters(true);
- const size_t kNumRpcsPerAddress = 10;
- const size_t kNumFailuresPerAddress = 3;
- // TODO(juanlishen): Partition the backends after multiple localities is
- // tested.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until all backends are ready.
- size_t num_warmup_rpcs = WaitForAllBackends();
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * num_backends_);
- CheckRpcSendFailure(CheckRpcSendFailureOptions()
- .set_times(kNumFailuresPerAddress * num_backends_)
- .set_rpc_options(RpcOptions().set_server_fail(true)));
- // Check that each backend got the right number of requests.
- for (size_t i = 0; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress + kNumFailuresPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- // The load report received at the balancer should be correct.
- std::vector<ClientStats> load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(load_report.size(), 1UL);
- ClientStats& client_stats = load_report.front();
- EXPECT_EQ(kNumRpcsPerAddress * num_backends_ + num_warmup_rpcs,
- client_stats.total_successful_requests());
- EXPECT_EQ(0U, client_stats.total_requests_in_progress());
- EXPECT_EQ((kNumRpcsPerAddress + kNumFailuresPerAddress) * num_backends_ +
- num_warmup_rpcs,
- client_stats.total_issued_requests());
- EXPECT_EQ(kNumFailuresPerAddress * num_backends_,
- client_stats.total_error_requests());
- EXPECT_EQ(0U, client_stats.total_dropped_requests());
- // The LRS service got a single request, and sent a single response.
- EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
- }
- // Tests that we don't include stats for clusters that are not requested
- // by the LRS server.
- TEST_P(ClientLoadReportingTest, HonorsClustersRequestedByLrsServer) {
- balancer_->lrs_service()->set_cluster_names({"bogus"});
- const size_t kNumRpcsPerAddress = 100;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until all backends are ready.
- WaitForAllBackends();
- // Send kNumRpcsPerAddress RPCs per server.
- CheckRpcSendOk(kNumRpcsPerAddress * num_backends_);
- // Each backend should have gotten 100 requests.
- for (size_t i = 0; i < backends_.size(); ++i) {
- EXPECT_EQ(kNumRpcsPerAddress,
- backends_[i]->backend_service()->request_count());
- }
- // The LRS service got a single request, and sent a single response.
- EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
- // The load report received at the balancer should be correct.
- std::vector<ClientStats> load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(load_report.size(), 0UL);
- }
- // Tests that if the balancer restarts, the client load report contains the
- // stats before and after the restart correctly.
- TEST_P(ClientLoadReportingTest, BalancerRestart) {
- const size_t kNumBackendsFirstPass = backends_.size() / 2;
- const size_t kNumBackendsSecondPass =
- backends_.size() - kNumBackendsFirstPass;
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, kNumBackendsFirstPass)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait until all backends returned by the balancer are ready.
- size_t num_rpcs = WaitForAllBackends(
- /*start_index=*/0, /*stop_index=*/kNumBackendsFirstPass);
- std::vector<ClientStats> load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(load_report.size(), 1UL);
- ClientStats client_stats = std::move(load_report.front());
- EXPECT_EQ(num_rpcs, client_stats.total_successful_requests());
- EXPECT_EQ(0U, client_stats.total_requests_in_progress());
- EXPECT_EQ(0U, client_stats.total_error_requests());
- EXPECT_EQ(0U, client_stats.total_dropped_requests());
- // Shut down the balancer.
- balancer_->Shutdown();
- // We should continue using the last EDS response we received from the
- // balancer before it was shut down.
- // Note: We need to use WaitForAllBackends() here instead of just
- // CheckRpcSendOk(kNumBackendsFirstPass), because when the balancer
- // shuts down, the XdsClient will generate an error to the
- // ServiceConfigWatcher, which will cause the xds resolver to send a
- // no-op update to the LB policy. When this update gets down to the
- // round_robin child policy for the locality, it will generate a new
- // subchannel list, which resets the start index randomly. So we need
- // to be a little more permissive here to avoid spurious failures.
- ResetBackendCounters();
- num_rpcs = WaitForAllBackends(/*start_index=*/0,
- /*stop_index=*/kNumBackendsFirstPass);
- // Now restart the balancer, this time pointing to the new backends.
- balancer_->Start();
- args = EdsResourceArgs({
- {"locality0", CreateEndpointsForBackends(kNumBackendsFirstPass)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Wait for queries to start going to one of the new backends.
- // This tells us that we're now using the new serverlist.
- num_rpcs += WaitForAllBackends(/*start_index=*/kNumBackendsFirstPass);
- // Send one RPC per backend.
- CheckRpcSendOk(kNumBackendsSecondPass);
- num_rpcs += kNumBackendsSecondPass;
- // Check client stats.
- load_report = balancer_->lrs_service()->WaitForLoadReport();
- ASSERT_EQ(load_report.size(), 1UL);
- client_stats = std::move(load_report.front());
- EXPECT_EQ(num_rpcs, client_stats.total_successful_requests());
- EXPECT_EQ(0U, client_stats.total_requests_in_progress());
- EXPECT_EQ(0U, client_stats.total_error_requests());
- EXPECT_EQ(0U, client_stats.total_dropped_requests());
- }
- // Tests load reporting when switching over from one cluster to another.
- TEST_P(ClientLoadReportingTest, ChangeClusters) {
- const char* kNewClusterName = "new_cluster_name";
- const char* kNewEdsServiceName = "new_eds_service_name";
- balancer_->lrs_service()->set_cluster_names(
- {kDefaultClusterName, kNewClusterName});
- // cluster kDefaultClusterName -> locality0 -> backends 0 and 1
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends(0, 2)},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // cluster kNewClusterName -> locality1 -> backends 2 and 3
- EdsResourceArgs args2({
- {"locality1", CreateEndpointsForBackends(2, 4)},
- });
- balancer_->ads_service()->SetEdsResource(
- BuildEdsResource(args2, kNewEdsServiceName));
- // CDS resource for kNewClusterName.
- Cluster new_cluster = default_cluster_;
- new_cluster.set_name(kNewClusterName);
- new_cluster.mutable_eds_cluster_config()->set_service_name(
- kNewEdsServiceName);
- balancer_->ads_service()->SetCdsResource(new_cluster);
- // Wait for all backends to come online.
- size_t num_rpcs = WaitForAllBackends(0, 2);
- // The load report received at the balancer should be correct.
- std::vector<ClientStats> load_report =
- balancer_->lrs_service()->WaitForLoadReport();
- EXPECT_THAT(
- load_report,
- ::testing::ElementsAre(::testing::AllOf(
- ::testing::Property(&ClientStats::cluster_name, kDefaultClusterName),
- ::testing::Property(
- &ClientStats::locality_stats,
- ::testing::ElementsAre(::testing::Pair(
- "locality0",
- ::testing::AllOf(
- ::testing::Field(&ClientStats::LocalityStats::
- total_successful_requests,
- num_rpcs),
- ::testing::Field(&ClientStats::LocalityStats::
- total_requests_in_progress,
- 0UL),
- ::testing::Field(
- &ClientStats::LocalityStats::total_error_requests,
- 0UL),
- ::testing::Field(
- &ClientStats::LocalityStats::total_issued_requests,
- num_rpcs))))),
- ::testing::Property(&ClientStats::total_dropped_requests, 0UL))));
- // Change RDS resource to point to new cluster.
- RouteConfiguration new_route_config = default_route_config_;
- new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_route()
- ->set_cluster(kNewClusterName);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_,
- new_route_config);
- // Wait for all new backends to be used.
- num_rpcs = WaitForAllBackends(2, 4);
- // The load report received at the balancer should be correct.
- load_report = balancer_->lrs_service()->WaitForLoadReport();
- EXPECT_THAT(
- load_report,
- ::testing::ElementsAre(
- ::testing::AllOf(
- ::testing::Property(&ClientStats::cluster_name,
- kDefaultClusterName),
- ::testing::Property(
- &ClientStats::locality_stats,
- ::testing::ElementsAre(::testing::Pair(
- "locality0",
- ::testing::AllOf(
- ::testing::Field(&ClientStats::LocalityStats::
- total_successful_requests,
- ::testing::Lt(num_rpcs)),
- ::testing::Field(&ClientStats::LocalityStats::
- total_requests_in_progress,
- 0UL),
- ::testing::Field(
- &ClientStats::LocalityStats::total_error_requests,
- 0UL),
- ::testing::Field(&ClientStats::LocalityStats::
- total_issued_requests,
- ::testing::Le(num_rpcs)))))),
- ::testing::Property(&ClientStats::total_dropped_requests, 0UL)),
- ::testing::AllOf(
- ::testing::Property(&ClientStats::cluster_name, kNewClusterName),
- ::testing::Property(
- &ClientStats::locality_stats,
- ::testing::ElementsAre(::testing::Pair(
- "locality1",
- ::testing::AllOf(
- ::testing::Field(&ClientStats::LocalityStats::
- total_successful_requests,
- ::testing::Le(num_rpcs)),
- ::testing::Field(&ClientStats::LocalityStats::
- total_requests_in_progress,
- 0UL),
- ::testing::Field(
- &ClientStats::LocalityStats::total_error_requests,
- 0UL),
- ::testing::Field(&ClientStats::LocalityStats::
- total_issued_requests,
- ::testing::Le(num_rpcs)))))),
- ::testing::Property(&ClientStats::total_dropped_requests, 0UL))));
- size_t total_ok = 0;
- for (const ClientStats& client_stats : load_report) {
- total_ok += client_stats.total_successful_requests();
- }
- EXPECT_EQ(total_ok, num_rpcs);
- // The LRS service got a single request, and sent a single response.
- EXPECT_EQ(1U, balancer_->lrs_service()->request_count());
- EXPECT_EQ(1U, balancer_->lrs_service()->response_count());
- }
- class ClientLoadReportingWithDropTest : public XdsEnd2endTest {
- public:
- ClientLoadReportingWithDropTest() : XdsEnd2endTest(4, 20) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- };
- // Tests that the drop stats are correctly reported by client load reporting.
- TEST_P(ClientLoadReportingWithDropTest, Vanilla) {
- const uint32_t kDropPerMillionForLb = 100000;
- const uint32_t kDropPerMillionForThrottle = 200000;
- const double kErrorTolerance = 0.05;
- const double kDropRateForLb = kDropPerMillionForLb / 1000000.0;
- const double kDropRateForThrottle = kDropPerMillionForThrottle / 1000000.0;
- const double kDropRateForLbAndThrottle =
- kDropRateForLb + (1 - kDropRateForLb) * kDropRateForThrottle;
- const size_t kNumRpcs =
- ComputeIdealNumRpcs(kDropRateForLbAndThrottle, kErrorTolerance);
- const char kStatusMessageDropPrefix[] = "EDS-configured drop: ";
- // The ADS response contains two drop categories.
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- args.drop_categories = {{kLbDropType, kDropPerMillionForLb},
- {kThrottleDropType, kDropPerMillionForThrottle}};
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send kNumRpcs RPCs and count the drops.
- size_t num_drops =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, kStatusMessageDropPrefix);
- // The drop rate should be roughly equal to the expectation.
- const double seen_drop_rate = static_cast<double>(num_drops) / kNumRpcs;
- EXPECT_THAT(seen_drop_rate, ::testing::DoubleNear(kDropRateForLbAndThrottle,
- kErrorTolerance));
- // Check client stats.
- ClientStats client_stats;
- do {
- std::vector<ClientStats> load_reports =
- balancer_->lrs_service()->WaitForLoadReport();
- for (const auto& load_report : load_reports) {
- client_stats += load_report;
- }
- } while (client_stats.total_issued_requests() +
- client_stats.total_dropped_requests() <
- kNumRpcs);
- EXPECT_EQ(num_drops, client_stats.total_dropped_requests());
- EXPECT_THAT(static_cast<double>(client_stats.dropped_requests(kLbDropType)) /
- kNumRpcs,
- ::testing::DoubleNear(kDropRateForLb, kErrorTolerance));
- EXPECT_THAT(
- static_cast<double>(client_stats.dropped_requests(kThrottleDropType)) /
- (kNumRpcs * (1 - kDropRateForLb)),
- ::testing::DoubleNear(kDropRateForThrottle, kErrorTolerance));
- }
- class FaultInjectionTest : public XdsEnd2endTest {
- public:
- FaultInjectionTest() : XdsEnd2endTest(1) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- // Builds a Listener with Fault Injection filter config. If the http_fault
- // is nullptr, then assign an empty filter config. This filter config is
- // required to enable the fault injection features.
- static Listener BuildListenerWithFaultInjection(
- const HTTPFault& http_fault = HTTPFault()) {
- HttpConnectionManager http_connection_manager;
- Listener listener;
- listener.set_name(kServerName);
- HttpFilter* fault_filter = http_connection_manager.add_http_filters();
- fault_filter->set_name("envoy.fault");
- fault_filter->mutable_typed_config()->PackFrom(http_fault);
- HttpFilter* router_filter = http_connection_manager.add_http_filters();
- router_filter->set_name("router");
- router_filter->mutable_typed_config()->PackFrom(
- envoy::extensions::filters::http::router::v3::Router());
- listener.mutable_api_listener()->mutable_api_listener()->PackFrom(
- http_connection_manager);
- return listener;
- }
- RouteConfiguration BuildRouteConfigurationWithFaultInjection(
- const HTTPFault& http_fault) {
- // Package as Any
- google::protobuf::Any filter_config;
- filter_config.PackFrom(http_fault);
- // Plug into the RouteConfiguration
- RouteConfiguration new_route_config = default_route_config_;
- auto* config_map = new_route_config.mutable_virtual_hosts(0)
- ->mutable_routes(0)
- ->mutable_typed_per_filter_config();
- (*config_map)["envoy.fault"] = std::move(filter_config);
- return new_route_config;
- }
- void SetFilterConfig(HTTPFault& http_fault) {
- switch (GetParam().filter_config_setup()) {
- case TestType::FilterConfigSetup::kRouteOverride: {
- Listener listener = BuildListenerWithFaultInjection();
- RouteConfiguration route =
- BuildRouteConfigurationWithFaultInjection(http_fault);
- SetListenerAndRouteConfiguration(balancer_.get(), listener, route);
- break;
- }
- case TestType::FilterConfigSetup::kHTTPConnectionManagerOriginal: {
- Listener listener = BuildListenerWithFaultInjection(http_fault);
- SetListenerAndRouteConfiguration(balancer_.get(), listener,
- default_route_config_);
- }
- };
- }
- };
- // Test to ensure the most basic fault injection config works.
- TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysAbort) {
- const uint32_t kAbortPercentagePerHundred = 100;
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(kAbortPercentagePerHundred);
- abort_percentage->set_denominator(FractionalPercent::HUNDRED);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Fire several RPCs, and expect all of them to be aborted.
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_times(5)
- .set_rpc_options(RpcOptions().set_wait_for_ready(true))
- .set_expected_error_code(StatusCode::ABORTED));
- }
- // Without the listener config, the fault injection won't be enabled.
- TEST_P(FaultInjectionTest, XdsFaultInjectionWithoutListenerFilter) {
- const uint32_t kAbortPercentagePerHundred = 100;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(kAbortPercentagePerHundred);
- abort_percentage->set_denominator(FractionalPercent::HUNDRED);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- // Turn on fault injection
- RouteConfiguration route =
- BuildRouteConfigurationWithFaultInjection(http_fault);
- SetListenerAndRouteConfiguration(balancer_.get(), default_listener_, route);
- // Fire several RPCs, and expect all of them to be pass.
- CheckRpcSendOk(5, RpcOptions().set_wait_for_ready(true));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbort) {
- const uint32_t kAbortPercentagePerHundred = 50;
- const double kAbortRate = kAbortPercentagePerHundred / 100.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(kAbortPercentagePerHundred);
- abort_percentage->set_denominator(FractionalPercent::HUNDRED);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Send kNumRpcs RPCs and count the aborts.
- size_t num_aborted =
- SendRpcsAndCountFailuresWithMessage(kNumRpcs, "Fault injected");
- // The abort rate should be roughly equal to the expectation.
- const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
- EXPECT_THAT(seen_abort_rate,
- ::testing::DoubleNear(kAbortRate, kErrorTolerance));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageAbortViaHeaders) {
- const uint32_t kAbortPercentageCap = 100;
- const uint32_t kAbortPercentage = 50;
- const double kAbortRate = kAbortPercentage / 100.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- http_fault.mutable_abort()->mutable_header_abort();
- http_fault.mutable_abort()->mutable_percentage()->set_numerator(
- kAbortPercentageCap);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Send kNumRpcs RPCs and count the aborts.
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"x-envoy-fault-abort-grpc-request", "10"},
- {"x-envoy-fault-abort-percentage", std::to_string(kAbortPercentage)},
- };
- size_t num_aborted = SendRpcsAndCountFailuresWithMessage(
- kNumRpcs, "Fault injected", RpcOptions().set_metadata(metadata));
- // The abort rate should be roughly equal to the expectation.
- const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
- EXPECT_THAT(seen_abort_rate,
- ::testing::DoubleNear(kAbortRate, kErrorTolerance));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelay) {
- const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
- const uint32_t kFixedDelaySeconds = 100;
- const uint32_t kDelayPercentagePerHundred = 50;
- const double kDelayRate = kDelayPercentagePerHundred / 100.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
- const size_t kMaxConcurrentRequests = kNumRpcs;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Loosen the max concurrent request limit
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(kDelayPercentagePerHundred);
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Send kNumRpcs RPCs and count the delays.
- RpcOptions rpc_options = RpcOptions()
- .set_timeout_ms(kRpcTimeoutMilliseconds)
- .set_skip_cancelled_check(true);
- std::vector<ConcurrentRpc> rpcs =
- SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
- size_t num_delayed = 0;
- for (auto& rpc : rpcs) {
- if (rpc.status.error_code() == StatusCode::OK) continue;
- EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
- ++num_delayed;
- }
- // The delay rate should be roughly equal to the expectation.
- const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
- EXPECT_THAT(seen_delay_rate,
- ::testing::DoubleNear(kDelayRate, kErrorTolerance));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionPercentageDelayViaHeaders) {
- const uint32_t kFixedDelayMilliseconds = 100000;
- const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 3000;
- const uint32_t kDelayPercentageCap = 100;
- const uint32_t kDelayPercentage = 50;
- const double kDelayRate = kDelayPercentage / 100.0;
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kDelayRate, kErrorTolerance);
- const size_t kMaxConcurrentRequests = kNumRpcs;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Loosen the max concurrent request limit
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Construct the fault injection filter config
- HTTPFault http_fault;
- http_fault.mutable_delay()->mutable_header_delay();
- http_fault.mutable_delay()->mutable_percentage()->set_numerator(
- kDelayPercentageCap);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Send kNumRpcs RPCs and count the delays.
- std::vector<std::pair<std::string, std::string>> metadata = {
- {"x-envoy-fault-delay-request", std::to_string(kFixedDelayMilliseconds)},
- {"x-envoy-fault-delay-request-percentage",
- std::to_string(kDelayPercentage)},
- };
- RpcOptions rpc_options = RpcOptions()
- .set_metadata(metadata)
- .set_timeout_ms(kRpcTimeoutMilliseconds)
- .set_skip_cancelled_check(true);
- std::vector<ConcurrentRpc> rpcs =
- SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
- size_t num_delayed = 0;
- for (auto& rpc : rpcs) {
- if (rpc.status.error_code() == StatusCode::OK) continue;
- EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
- ++num_delayed;
- }
- // The delay rate should be roughly equal to the expectation.
- const double seen_delay_rate = static_cast<double>(num_delayed) / kNumRpcs;
- EXPECT_THAT(seen_delay_rate,
- ::testing::DoubleNear(kDelayRate, kErrorTolerance));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionAbortAfterDelayForStreamCall) {
- const uint32_t kFixedDelaySeconds = 1;
- const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(100); // Always inject ABORT!
- abort_percentage->set_denominator(FractionalPercent::HUNDRED);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(100); // Always inject DELAY!
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Send a stream RPC and check its status code
- ClientContext context;
- context.set_deadline(
- grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
- auto stream = stub_->BidiStream(&context);
- stream->WritesDone();
- auto status = stream->Finish();
- EXPECT_EQ(StatusCode::ABORTED, status.error_code())
- << status.error_message() << ", " << status.error_details() << ", "
- << context.debug_error_string();
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionAlwaysDelayPercentageAbort) {
- const uint32_t kAbortPercentagePerHundred = 50;
- const double kAbortRate = kAbortPercentagePerHundred / 100.0;
- const uint32_t kFixedDelaySeconds = 1;
- const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
- const uint32_t kConnectionTimeoutMilliseconds =
- 10 * 1000; // 10s should not reach
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
- const size_t kMaxConcurrentRequests = kNumRpcs;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Loosen the max concurrent request limit
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(kAbortPercentagePerHundred);
- abort_percentage->set_denominator(FractionalPercent::HUNDRED);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(1000000); // Always inject DELAY!
- delay_percentage->set_denominator(FractionalPercent::MILLION);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Allow the channel to connect to one backends, so the herd of queued RPCs
- // won't be executed on the same ExecCtx object and using the cached Now()
- // value, which causes millisecond level delay error.
- channel_->WaitForConnected(
- grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
- // Send kNumRpcs RPCs and count the aborts.
- int num_aborted = 0;
- RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
- std::vector<ConcurrentRpc> rpcs =
- SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
- for (auto& rpc : rpcs) {
- EXPECT_GE(rpc.elapsed_time,
- grpc_core::Duration::Seconds(kFixedDelaySeconds));
- if (rpc.status.error_code() == StatusCode::OK) continue;
- EXPECT_EQ("Fault injected", rpc.status.error_message());
- ++num_aborted;
- }
- // The abort rate should be roughly equal to the expectation.
- const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
- EXPECT_THAT(seen_abort_rate,
- ::testing::DoubleNear(kAbortRate, kErrorTolerance));
- }
- // This test and the above test apply different denominators to delay and
- // abort. This ensures that we are using the right denominator for each
- // injected fault in our code.
- TEST_P(FaultInjectionTest,
- XdsFaultInjectionAlwaysDelayPercentageAbortSwitchDenominator) {
- const uint32_t kAbortPercentagePerMillion = 500000;
- const double kAbortRate = kAbortPercentagePerMillion / 1000000.0;
- const uint32_t kFixedDelaySeconds = 1; // 1s
- const uint32_t kRpcTimeoutMilliseconds = 100 * 1000; // 100s should not reach
- const uint32_t kConnectionTimeoutMilliseconds =
- 10 * 1000; // 10s should not reach
- const double kErrorTolerance = 0.05;
- const size_t kNumRpcs = ComputeIdealNumRpcs(kAbortRate, kErrorTolerance);
- const size_t kMaxConcurrentRequests = kNumRpcs;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Loosen the max concurrent request limit
- Cluster cluster = default_cluster_;
- auto* threshold = cluster.mutable_circuit_breakers()->add_thresholds();
- threshold->set_priority(RoutingPriority::DEFAULT);
- threshold->mutable_max_requests()->set_value(kMaxConcurrentRequests);
- balancer_->ads_service()->SetCdsResource(cluster);
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* abort_percentage = http_fault.mutable_abort()->mutable_percentage();
- abort_percentage->set_numerator(kAbortPercentagePerMillion);
- abort_percentage->set_denominator(FractionalPercent::MILLION);
- http_fault.mutable_abort()->set_grpc_status(
- static_cast<uint32_t>(StatusCode::ABORTED));
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(100); // Always inject DELAY!
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Allow the channel to connect to one backends, so the herd of queued RPCs
- // won't be executed on the same ExecCtx object and using the cached Now()
- // value, which causes millisecond level delay error.
- channel_->WaitForConnected(
- grpc_timeout_milliseconds_to_deadline(kConnectionTimeoutMilliseconds));
- // Send kNumRpcs RPCs and count the aborts.
- int num_aborted = 0;
- RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMilliseconds);
- std::vector<ConcurrentRpc> rpcs =
- SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
- for (auto& rpc : rpcs) {
- EXPECT_GE(rpc.elapsed_time,
- grpc_core::Duration::Seconds(kFixedDelaySeconds));
- if (rpc.status.error_code() == StatusCode::OK) continue;
- EXPECT_EQ("Fault injected", rpc.status.error_message());
- ++num_aborted;
- }
- // The abort rate should be roughly equal to the expectation.
- const double seen_abort_rate = static_cast<double>(num_aborted) / kNumRpcs;
- EXPECT_THAT(seen_abort_rate,
- ::testing::DoubleNear(kAbortRate, kErrorTolerance));
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionMaxFault) {
- const uint32_t kMaxFault = 10;
- const uint32_t kNumRpcs = 30; // kNumRpcs should be bigger than kMaxFault
- const uint32_t kRpcTimeoutMs = 4000; // 4 seconds
- const uint32_t kLongDelaySeconds = 100; // 100 seconds
- const uint32_t kAlwaysDelayPercentage = 100;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(
- kAlwaysDelayPercentage); // Always inject DELAY!
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kLongDelaySeconds);
- http_fault.mutable_max_active_faults()->set_value(kMaxFault);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- // Sends a batch of long running RPCs with long timeout to consume all
- // active faults quota.
- int num_delayed = 0;
- RpcOptions rpc_options = RpcOptions().set_timeout_ms(kRpcTimeoutMs);
- std::vector<ConcurrentRpc> rpcs =
- SendConcurrentRpcs(stub_.get(), kNumRpcs, rpc_options);
- for (auto& rpc : rpcs) {
- if (rpc.status.error_code() == StatusCode::OK) continue;
- EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, rpc.status.error_code());
- ++num_delayed;
- }
- // Only kMaxFault number of RPC should be fault injected..
- EXPECT_EQ(kMaxFault, num_delayed);
- }
- TEST_P(FaultInjectionTest, XdsFaultInjectionBidiStreamDelayOk) {
- // kRpcTimeoutMilliseconds is 10s should never be reached.
- const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 10000;
- const uint32_t kFixedDelaySeconds = 1;
- const uint32_t kDelayPercentagePerHundred = 100;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(kDelayPercentagePerHundred);
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- ClientContext context;
- context.set_deadline(
- grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
- auto stream = stub_->BidiStream(&context);
- stream->WritesDone();
- auto status = stream->Finish();
- EXPECT_TRUE(status.ok()) << status.error_message() << ", "
- << status.error_details() << ", "
- << context.debug_error_string();
- }
- // This case catches a bug in the retry code that was triggered by a bad
- // interaction with the FI code. See https://github.com/grpc/grpc/pull/27217
- // for description.
- TEST_P(FaultInjectionTest, XdsFaultInjectionBidiStreamDelayError) {
- const uint32_t kRpcTimeoutMilliseconds = grpc_test_slowdown_factor() * 500;
- const uint32_t kFixedDelaySeconds = 100;
- const uint32_t kDelayPercentagePerHundred = 100;
- // Create an EDS resource
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Construct the fault injection filter config
- HTTPFault http_fault;
- auto* delay_percentage = http_fault.mutable_delay()->mutable_percentage();
- delay_percentage->set_numerator(kDelayPercentagePerHundred);
- delay_percentage->set_denominator(FractionalPercent::HUNDRED);
- auto* fixed_delay = http_fault.mutable_delay()->mutable_fixed_delay();
- fixed_delay->set_seconds(kFixedDelaySeconds);
- // Config fault injection via different setup
- SetFilterConfig(http_fault);
- ClientContext context;
- context.set_deadline(
- grpc_timeout_milliseconds_to_deadline(kRpcTimeoutMilliseconds));
- auto stream = stub_->BidiStream(&context);
- stream->WritesDone();
- auto status = stream->Finish();
- EXPECT_EQ(StatusCode::DEADLINE_EXCEEDED, status.error_code())
- << status.error_message() << ", " << status.error_details() << ", "
- << context.debug_error_string();
- }
- class BootstrapSourceTest : public XdsEnd2endTest {
- public:
- BootstrapSourceTest() : XdsEnd2endTest(4) {}
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- };
- TEST_P(BootstrapSourceTest, Vanilla) {
- EdsResourceArgs args({
- {"locality0", CreateEndpointsForBackends()},
- });
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- WaitForAllBackends();
- }
- #ifndef DISABLED_XDS_PROTO_IN_CC
- class ClientStatusDiscoveryServiceTest : public XdsEnd2endTest {
- public:
- explicit ClientStatusDiscoveryServiceTest(
- int xds_resource_does_not_exist_timeout_ms = 0)
- : XdsEnd2endTest(1, 100, xds_resource_does_not_exist_timeout_ms) {
- admin_server_thread_ = absl::make_unique<AdminServerThread>(this);
- admin_server_thread_->Start();
- std::string admin_server_address = absl::StrCat(
- ipv6_only_ ? "[::1]:" : "127.0.0.1:", admin_server_thread_->port());
- admin_channel_ = grpc::CreateChannel(
- admin_server_address,
- std::make_shared<SecureChannelCredentials>(
- grpc_fake_transport_security_credentials_create()));
- csds_stub_ =
- envoy::service::status::v3::ClientStatusDiscoveryService::NewStub(
- admin_channel_);
- if (GetParam().use_csds_streaming()) {
- stream_ = csds_stub_->StreamClientStatus(&stream_context_);
- }
- }
- void SetUp() override {
- XdsEnd2endTest::SetUp();
- StartAllBackends();
- }
- ~ClientStatusDiscoveryServiceTest() override {
- if (stream_ != nullptr) {
- EXPECT_TRUE(stream_->WritesDone());
- Status status = stream_->Finish();
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- }
- admin_server_thread_->Shutdown();
- }
- envoy::service::status::v3::ClientStatusResponse FetchCsdsResponse() {
- envoy::service::status::v3::ClientStatusResponse response;
- if (!GetParam().use_csds_streaming()) {
- // Fetch through unary pulls
- ClientContext context;
- Status status = csds_stub_->FetchClientStatus(
- &context, envoy::service::status::v3::ClientStatusRequest(),
- &response);
- EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
- << " message=" << status.error_message();
- } else {
- // Fetch through streaming pulls
- EXPECT_TRUE(
- stream_->Write(envoy::service::status::v3::ClientStatusRequest()));
- EXPECT_TRUE(stream_->Read(&response));
- }
- return response;
- }
- private:
- std::unique_ptr<AdminServerThread> admin_server_thread_;
- std::shared_ptr<Channel> admin_channel_;
- std::unique_ptr<
- envoy::service::status::v3::ClientStatusDiscoveryService::Stub>
- csds_stub_;
- ClientContext stream_context_;
- std::unique_ptr<
- ClientReaderWriter<envoy::service::status::v3::ClientStatusRequest,
- envoy::service::status::v3::ClientStatusResponse>>
- stream_;
- };
- MATCHER_P4(EqNode, id, user_agent_name, user_agent_version, client_features,
- "equals Node") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(id, arg.id(), result_listener);
- ok &= ::testing::ExplainMatchResult(user_agent_name, arg.user_agent_name(),
- result_listener);
- ok &= ::testing::ExplainMatchResult(
- user_agent_version, arg.user_agent_version(), result_listener);
- ok &= ::testing::ExplainMatchResult(client_features, arg.client_features(),
- result_listener);
- return ok;
- }
- MATCHER_P6(EqGenericXdsConfig, type_url, name, version_info, xds_config,
- client_status, error_state, "equals GenericXdsConfig") {
- bool ok = true;
- ok &=
- ::testing::ExplainMatchResult(type_url, arg.type_url(), result_listener);
- ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
- ok &= ::testing::ExplainMatchResult(version_info, arg.version_info(),
- result_listener);
- ok &= ::testing::ExplainMatchResult(xds_config, arg.xds_config(),
- result_listener);
- ok &= ::testing::ExplainMatchResult(client_status, arg.client_status(),
- result_listener);
- ok &= ::testing::ExplainMatchResult(error_state, arg.error_state(),
- result_listener);
- return ok;
- }
- MATCHER_P2(EqListener, name, api_listener, "equals Listener") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
- ok &= ::testing::ExplainMatchResult(
- api_listener, arg.api_listener().api_listener(), result_listener);
- return ok;
- }
- MATCHER_P(EqHttpConnectionManagerNotRds, route_config,
- "equals HttpConnectionManager") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(route_config, arg.route_config(),
- result_listener);
- return ok;
- }
- MATCHER_P(EqRouteConfigurationName, name, "equals RouteConfiguration") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
- return ok;
- }
- MATCHER_P2(EqRouteConfiguration, name, cluster_name,
- "equals RouteConfiguration") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
- ok &= ::testing::ExplainMatchResult(
- ::testing::ElementsAre(::testing::Property(
- &envoy::config::route::v3::VirtualHost::routes,
- ::testing::ElementsAre(::testing::Property(
- &envoy::config::route::v3::Route::route,
- ::testing::Property(
- &envoy::config::route::v3::RouteAction::cluster,
- cluster_name))))),
- arg.virtual_hosts(), result_listener);
- return ok;
- }
- MATCHER_P(EqCluster, name, "equals Cluster") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(name, arg.name(), result_listener);
- return ok;
- }
- MATCHER_P(EqEndpoint, port, "equals Endpoint") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(
- port, arg.address().socket_address().port_value(), result_listener);
- return ok;
- }
- MATCHER_P2(EqLocalityLbEndpoints, port, weight, "equals LocalityLbEndpoints") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(
- ::testing::ElementsAre(::testing::Property(
- &envoy::config::endpoint::v3::LbEndpoint::endpoint,
- EqEndpoint(port))),
- arg.lb_endpoints(), result_listener);
- ok &= ::testing::ExplainMatchResult(
- weight, arg.load_balancing_weight().value(), result_listener);
- return ok;
- }
- MATCHER_P(EqClusterLoadAssignmentName, cluster_name,
- "equals ClusterLoadAssignment") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(cluster_name, arg.cluster_name(),
- result_listener);
- return ok;
- }
- MATCHER_P3(EqClusterLoadAssignment, cluster_name, port, weight,
- "equals ClusterLoadAssignment") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(cluster_name, arg.cluster_name(),
- result_listener);
- ok &= ::testing::ExplainMatchResult(
- ::testing::ElementsAre(EqLocalityLbEndpoints(port, weight)),
- arg.endpoints(), result_listener);
- return ok;
- }
- MATCHER_P2(EqUpdateFailureState, details, version_info,
- "equals UpdateFailureState") {
- bool ok = true;
- ok &= ::testing::ExplainMatchResult(details, arg.details(), result_listener);
- ok &= ::testing::ExplainMatchResult(version_info, arg.version_info(),
- result_listener);
- return ok;
- }
- MATCHER_P(UnpackListener, matcher, "is a Listener") {
- Listener config;
- if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
- result_listener)) {
- return false;
- }
- return ::testing::ExplainMatchResult(matcher, config, result_listener);
- }
- MATCHER_P(UnpackRouteConfiguration, matcher, "is a RouteConfiguration") {
- RouteConfiguration config;
- if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
- result_listener)) {
- return false;
- }
- return ::testing::ExplainMatchResult(matcher, config, result_listener);
- }
- MATCHER_P(UnpackHttpConnectionManager, matcher, "is a HttpConnectionManager") {
- HttpConnectionManager config;
- if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
- result_listener)) {
- return false;
- }
- return ::testing::ExplainMatchResult(matcher, config, result_listener);
- }
- MATCHER_P(UnpackCluster, matcher, "is a Cluster") {
- Cluster config;
- if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
- result_listener)) {
- return false;
- }
- return ::testing::ExplainMatchResult(matcher, config, result_listener);
- }
- MATCHER_P(UnpackClusterLoadAssignment, matcher, "is a ClusterLoadAssignment") {
- ClusterLoadAssignment config;
- if (!::testing::ExplainMatchResult(true, arg.UnpackTo(&config),
- result_listener)) {
- return false;
- }
- return ::testing::ExplainMatchResult(matcher, config, result_listener);
- }
- MATCHER(IsRdsEnabledHCM, "is a RDS enabled HttpConnectionManager") {
- return ::testing::ExplainMatchResult(
- UnpackHttpConnectionManager(
- ::testing::Property(&HttpConnectionManager::has_rds, true)),
- arg, result_listener);
- }
- MATCHER_P2(EqNoRdsHCM, route_configuration_name, cluster_name,
- "equals RDS disabled HttpConnectionManager") {
- return ::testing::ExplainMatchResult(
- UnpackHttpConnectionManager(EqHttpConnectionManagerNotRds(
- EqRouteConfiguration(route_configuration_name, cluster_name))),
- arg, result_listener);
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpVanilla) {
- const size_t kNumRpcs = 5;
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Send several RPCs to ensure the xDS setup works
- CheckRpcSendOk(kNumRpcs);
- // Fetches the client config
- auto csds_response = FetchCsdsResponse();
- gpr_log(GPR_INFO, "xDS config dump: %s", csds_response.DebugString().c_str());
- EXPECT_EQ(1, csds_response.config_size());
- const auto& client_config = csds_response.config(0);
- // Validate the Node information
- EXPECT_THAT(client_config.node(),
- EqNode("xds_end2end_test", ::testing::HasSubstr("C-core"),
- ::testing::HasSubstr(grpc_version_string()),
- ::testing::ElementsAre(
- "envoy.lb.does_not_support_overprovisioning")));
- // Listener matcher depends on whether RDS is enabled.
- ::testing::Matcher<google::protobuf::Any> api_listener_matcher;
- if (GetParam().enable_rds_testing()) {
- api_listener_matcher = IsRdsEnabledHCM();
- } else {
- api_listener_matcher =
- EqNoRdsHCM(kDefaultRouteConfigurationName, kDefaultClusterName);
- }
- // Construct list of all matchers.
- std::vector<::testing::Matcher<
- envoy::service::status::v3::ClientConfig_GenericXdsConfig>>
- matchers = {
- // Listener
- EqGenericXdsConfig(
- kLdsTypeUrl, kServerName, "1",
- UnpackListener(EqListener(kServerName, api_listener_matcher)),
- ClientResourceStatus::ACKED, ::testing::_),
- // Cluster
- EqGenericXdsConfig(kCdsTypeUrl, kDefaultClusterName, "1",
- UnpackCluster(EqCluster(kDefaultClusterName)),
- ClientResourceStatus::ACKED, ::testing::_),
- // ClusterLoadAssignment
- EqGenericXdsConfig(
- kEdsTypeUrl, kDefaultEdsServiceName, "1",
- UnpackClusterLoadAssignment(EqClusterLoadAssignment(
- kDefaultEdsServiceName, backends_[0]->port(),
- kDefaultLocalityWeight)),
- ClientResourceStatus::ACKED, ::testing::_),
- };
- // If RDS is enabled, add matcher for RDS resource.
- if (GetParam().enable_rds_testing()) {
- matchers.push_back(EqGenericXdsConfig(
- kRdsTypeUrl, kDefaultRouteConfigurationName, "1",
- UnpackRouteConfiguration(EqRouteConfiguration(
- kDefaultRouteConfigurationName, kDefaultClusterName)),
- ClientResourceStatus::ACKED, ::testing::_));
- }
- // Validate the dumped xDS configs
- EXPECT_THAT(client_config.generic_xds_configs(),
- ::testing::UnorderedElementsAreArray(matchers))
- << "Actual: " << client_config.DebugString();
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpEmpty) {
- // The CSDS service should not fail if XdsClient is not initialized or there
- // is no working xDS configs.
- FetchCsdsResponse();
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerError) {
- int kFetchConfigRetries = 3;
- int kFetchIntervalMilliseconds = 200;
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Ensure the xDS resolver has working configs.
- CheckRpcSendOk();
- // Bad Listener should be rejected.
- Listener listener;
- listener.set_name(kServerName);
- balancer_->ads_service()->SetLdsResource(listener);
- // The old xDS configs should still be effective.
- CheckRpcSendOk();
- ::testing::Matcher<google::protobuf::Any> api_listener_matcher;
- if (GetParam().enable_rds_testing()) {
- api_listener_matcher = IsRdsEnabledHCM();
- } else {
- api_listener_matcher =
- EqNoRdsHCM(kDefaultRouteConfigurationName, kDefaultClusterName);
- }
- for (int i = 0; i < kFetchConfigRetries; ++i) {
- auto csds_response = FetchCsdsResponse();
- // Check if error state is propagated
- bool ok = ::testing::Value(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kLdsTypeUrl, kServerName, "1",
- UnpackListener(EqListener(kServerName, api_listener_matcher)),
- ClientResourceStatus::NACKED,
- EqUpdateFailureState(
- ::testing::HasSubstr(
- "Listener has neither address nor ApiListener"),
- "2"))));
- if (ok) return; // TEST PASSED!
- gpr_sleep_until(
- grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
- }
- FAIL() << "error_state not seen in CSDS responses";
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpRouteError) {
- int kFetchConfigRetries = 3;
- int kFetchIntervalMilliseconds = 200;
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Ensure the xDS resolver has working configs.
- CheckRpcSendOk();
- // Bad route config will be rejected.
- RouteConfiguration route_config;
- route_config.set_name(kDefaultRouteConfigurationName);
- route_config.add_virtual_hosts();
- SetRouteConfiguration(balancer_.get(), route_config);
- // The old xDS configs should still be effective.
- CheckRpcSendOk();
- for (int i = 0; i < kFetchConfigRetries; ++i) {
- auto csds_response = FetchCsdsResponse();
- bool ok = false;
- if (GetParam().enable_rds_testing()) {
- ok = ::testing::Value(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kRdsTypeUrl, kDefaultRouteConfigurationName, "1",
- UnpackRouteConfiguration(EqRouteConfiguration(
- kDefaultRouteConfigurationName, kDefaultClusterName)),
- ClientResourceStatus::NACKED,
- EqUpdateFailureState(
- ::testing::HasSubstr("VirtualHost has no domains"), "2"))));
- } else {
- ok = ::testing::Value(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kLdsTypeUrl, kServerName, "1",
- UnpackListener(EqListener(
- kServerName, EqNoRdsHCM(kDefaultRouteConfigurationName,
- kDefaultClusterName))),
- ClientResourceStatus::NACKED,
- EqUpdateFailureState(
- ::testing::HasSubstr("VirtualHost has no domains"), "2"))));
- }
- if (ok) return; // TEST PASSED!
- gpr_sleep_until(
- grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
- }
- FAIL() << "error_state not seen in CSDS responses";
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterError) {
- int kFetchConfigRetries = 3;
- int kFetchIntervalMilliseconds = 200;
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Ensure the xDS resolver has working configs.
- CheckRpcSendOk();
- // Listener without any route, will be rejected.
- Cluster cluster;
- cluster.set_name(kDefaultClusterName);
- balancer_->ads_service()->SetCdsResource(cluster);
- // The old xDS configs should still be effective.
- CheckRpcSendOk();
- for (int i = 0; i < kFetchConfigRetries; ++i) {
- auto csds_response = FetchCsdsResponse();
- // Check if error state is propagated
- bool ok = ::testing::Value(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kCdsTypeUrl, kDefaultClusterName, "1",
- UnpackCluster(EqCluster(kDefaultClusterName)),
- ClientResourceStatus::NACKED,
- EqUpdateFailureState(
- ::testing::HasSubstr("DiscoveryType not found"), "2"))));
- if (ok) return; // TEST PASSED!
- gpr_sleep_until(
- grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
- }
- FAIL() << "error_state not seen in CSDS responses";
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpEndpointError) {
- int kFetchConfigRetries = 3;
- int kFetchIntervalMilliseconds = 200;
- EdsResourceArgs args({{"locality0", CreateEndpointsForBackends(0, 1)}});
- balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
- // Ensure the xDS resolver has working configs.
- CheckRpcSendOk();
- // Bad endpoint config will be rejected.
- ClusterLoadAssignment cluster_load_assignment;
- cluster_load_assignment.set_cluster_name(kDefaultEdsServiceName);
- auto* endpoints = cluster_load_assignment.add_endpoints();
- endpoints->mutable_load_balancing_weight()->set_value(1);
- auto* endpoint = endpoints->add_lb_endpoints()->mutable_endpoint();
- endpoint->mutable_address()->mutable_socket_address()->set_port_value(1 << 1);
- balancer_->ads_service()->SetEdsResource(cluster_load_assignment);
- // The old xDS configs should still be effective.
- CheckRpcSendOk();
- for (int i = 0; i < kFetchConfigRetries; ++i) {
- auto csds_response = FetchCsdsResponse();
- // Check if error state is propagated
- bool ok = ::testing::Value(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kEdsTypeUrl, kDefaultEdsServiceName, "1",
- UnpackClusterLoadAssignment(EqClusterLoadAssignment(
- kDefaultEdsServiceName, backends_[0]->port(),
- kDefaultLocalityWeight)),
- ClientResourceStatus::NACKED,
- EqUpdateFailureState(::testing::HasSubstr("Empty locality"),
- "2"))));
- if (ok) return; // TEST PASSED!
- gpr_sleep_until(
- grpc_timeout_milliseconds_to_deadline(kFetchIntervalMilliseconds));
- }
- FAIL() << "error_state not seen in CSDS responses";
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpListenerRequested) {
- int kTimeoutMillisecond = 1000;
- balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kLdsTypeUrl, kServerName, ::testing::_, ::testing::_,
- ClientResourceStatus::REQUESTED, ::testing::_)));
- }
- TEST_P(ClientStatusDiscoveryServiceTest, XdsConfigDumpClusterRequested) {
- int kTimeoutMillisecond = 1000;
- std::string kClusterName1 = "cluster-1";
- std::string kClusterName2 = "cluster-2";
- // Create a route config requesting two non-existing clusters
- RouteConfiguration route_config;
- route_config.set_name(kDefaultRouteConfigurationName);
- auto* vh = route_config.add_virtual_hosts();
- // The VirtualHost must match the domain name, otherwise will cause resolver
- // transient failure.
- vh->add_domains("*");
- auto* routes1 = vh->add_routes();
- routes1->mutable_match()->set_prefix("");
- routes1->mutable_route()->set_cluster(kClusterName1);
- auto* routes2 = vh->add_routes();
- routes2->mutable_match()->set_prefix("");
- routes2->mutable_route()->set_cluster(kClusterName2);
- SetRouteConfiguration(balancer_.get(), route_config);
- // Try to get the configs plumb through
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(StatusCode::DEADLINE_EXCEEDED));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
- ::testing::AllOf(
- ::testing::Contains(EqGenericXdsConfig(
- kCdsTypeUrl, kClusterName1, ::testing::_, ::testing::_,
- ClientResourceStatus::REQUESTED, ::testing::_)),
- ::testing::Contains(EqGenericXdsConfig(
- kCdsTypeUrl, kClusterName2, ::testing::_, ::testing::_,
- ClientResourceStatus::REQUESTED, ::testing::_))));
- }
- class CsdsShortAdsTimeoutTest : public ClientStatusDiscoveryServiceTest {
- protected:
- // Shorten the ADS subscription timeout to speed up the test run.
- CsdsShortAdsTimeoutTest()
- : ClientStatusDiscoveryServiceTest(
- /* xds_resource_does_not_exist_timeout_ms_ = */ 2000) {}
- };
- TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpListenerDoesNotExist) {
- int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
- balancer_->ads_service()->UnsetResource(kLdsTypeUrl, kServerName);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(grpc::StatusCode::UNAVAILABLE));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kLdsTypeUrl, kServerName, ::testing::_, ::testing::_,
- ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
- }
- TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpRouteConfigDoesNotExist) {
- if (!GetParam().enable_rds_testing()) return;
- int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
- balancer_->ads_service()->UnsetResource(kRdsTypeUrl,
- kDefaultRouteConfigurationName);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(grpc::StatusCode::UNAVAILABLE));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kRdsTypeUrl, kDefaultRouteConfigurationName, ::testing::_,
- ::testing::_, ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
- }
- TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpClusterDoesNotExist) {
- int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
- balancer_->ads_service()->UnsetResource(kCdsTypeUrl, kDefaultClusterName);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(grpc::StatusCode::UNAVAILABLE));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kCdsTypeUrl, kDefaultClusterName, ::testing::_, ::testing::_,
- ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
- }
- TEST_P(CsdsShortAdsTimeoutTest, XdsConfigDumpEndpointDoesNotExist) {
- int kTimeoutMillisecond = 1000000; // 1000s wait for the transient failure.
- balancer_->ads_service()->UnsetResource(kEdsTypeUrl, kDefaultEdsServiceName);
- CheckRpcSendFailure(
- CheckRpcSendFailureOptions()
- .set_rpc_options(RpcOptions().set_timeout_ms(kTimeoutMillisecond))
- .set_expected_error_code(grpc::StatusCode::UNAVAILABLE));
- auto csds_response = FetchCsdsResponse();
- EXPECT_THAT(
- csds_response.config(0).generic_xds_configs(),
- ::testing::Contains(EqGenericXdsConfig(
- kEdsTypeUrl, kDefaultEdsServiceName, ::testing::_, ::testing::_,
- ClientResourceStatus::DOES_NOT_EXIST, ::testing::_)));
- }
- #endif // DISABLED_XDS_PROTO_IN_CC
- std::string TestTypeName(const ::testing::TestParamInfo<TestType>& info) {
- return info.param.AsString();
- }
- // Run both with and without load reporting.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, BasicTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- // Don't run with load reporting or v2 or RDS, since they are irrelevant to
- // the tests.
- INSTANTIATE_TEST_SUITE_P(XdsTest, SecureNamingTest,
- ::testing::Values(TestType()), &TestTypeName);
- // LDS depends on XdsResolver.
- INSTANTIATE_TEST_SUITE_P(XdsTest, LdsTest, ::testing::Values(TestType()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(XdsTest, LdsV2Test,
- ::testing::Values(TestType().set_use_v2()),
- &TestTypeName);
- // LDS/RDS commmon tests depend on XdsResolver.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, LdsRdsTest,
- ::testing::Values(TestType(), TestType().set_enable_rds_testing(),
- // Also test with xDS v2.
- TestType().set_enable_rds_testing().set_use_v2()),
- &TestTypeName);
- // CDS depends on XdsResolver.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, CdsTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- // CDS depends on XdsResolver.
- // Security depends on v3.
- // Not enabling load reporting or RDS, since those are irrelevant to these
- // tests.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsSecurityTest,
- ::testing::Values(TestType().set_use_xds_credentials()), &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var, so that we use a global XdsClient
- // instance. Otherwise, we would need to use a separate fake resolver
- // result generator on the client and server sides.
- INSTANTIATE_TEST_SUITE_P(XdsTest, XdsEnabledServerTest,
- ::testing::Values(TestType().set_bootstrap_source(
- TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var so that we use one XdsClient.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsServerSecurityTest,
- ::testing::Values(TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_xds_credentials()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsEnabledServerStatusNotificationTest,
- ::testing::Values(TestType().set_use_xds_credentials()), &TestTypeName);
- // Run with bootstrap from env var so that we use one XdsClient.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsServerFilterChainMatchTest,
- ::testing::Values(TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_xds_credentials()),
- &TestTypeName);
- // Test xDS-enabled server with and without RDS.
- // Run with bootstrap from env var so that we use one XdsClient.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsServerRdsTest,
- ::testing::Values(TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_xds_credentials(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_xds_credentials()
- .set_enable_rds_testing()),
- &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var, so that we use a global XdsClient
- // instance. Otherwise, we would need to use a separate fake resolver
- // result generator on the client and server sides.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsRbacTest,
- ::testing::Values(
- TestType().set_use_xds_credentials().set_bootstrap_source(
- TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var, so that we use a global XdsClient
- // instance. Otherwise, we would need to use a separate fake resolver
- // result generator on the client and server sides.
- // Note that we are simply using the default fake credentials instead of xds
- // credentials for NACK tests to avoid a mismatch between the client and the
- // server's security settings when using the WaitForNack() infrastructure.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsRbacNackTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType().set_enable_rds_testing().set_bootstrap_source(
- TestType::kBootstrapFromEnvVar),
- TestType()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_enable_rds_testing()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var, so that we use a global XdsClient
- // instance. Otherwise, we would need to use a separate fake resolver
- // result generator on the client and server sides.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsRbacTestWithRouteOverrideAlwaysPresent,
- ::testing::Values(
- TestType()
- .set_use_xds_credentials()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // We are only testing the server here.
- // Run with bootstrap from env var, so that we use a global XdsClient
- // instance. Otherwise, we would need to use a separate fake resolver
- // result generator on the client and server sides.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsRbacTestWithActionPermutations,
- ::testing::Values(
- TestType()
- .set_use_xds_credentials()
- .set_rbac_action(RBAC_Action_ALLOW)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_rbac_action(RBAC_Action_DENY)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_rbac_action(RBAC_Action_ALLOW)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_rbac_action(RBAC_Action_DENY)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_rbac_action(RBAC_Action_ALLOW)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_rbac_action(RBAC_Action_DENY)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_rbac_action(RBAC_Action_ALLOW)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_use_xds_credentials()
- .set_enable_rds_testing()
- .set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)
- .set_rbac_action(RBAC_Action_DENY)
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // EDS could be tested with or without XdsResolver, but the tests would
- // be the same either way, so we test it only with XdsResolver.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, EdsTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- // Test initial resource timeouts for each resource type.
- // Do this only for XdsResolver with RDS enabled, so that we can test
- // all resource types.
- // Run with V3 only, since the functionality is no different in V2.
- // Run with bootstrap from env var so that multiple channels share the same
- // XdsClient (needed for testing the timeout for the 2nd LDS and RDS resource).
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, TimeoutTest,
- ::testing::Values(TestType().set_enable_rds_testing().set_bootstrap_source(
- TestType::kBootstrapFromEnvVar)),
- &TestTypeName);
- // XdsResolverOnlyTest depends on XdsResolver.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsResolverOnlyTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- // Runs with bootstrap from env var, so that there's a global XdsClient.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, GlobalXdsClientTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_load_reporting()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsFederationTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_rds_testing()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, XdsFederationLoadReportingTest,
- ::testing::Values(TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_load_reporting(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_load_reporting()
- .set_enable_rds_testing()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, LocalityMapTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, FailoverTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, DropTest,
- ::testing::Values(TestType(), TestType().set_enable_load_reporting()),
- &TestTypeName);
- // Load reporting tests are not run with load reporting disabled.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, ClientLoadReportingTest,
- ::testing::Values(TestType().set_enable_load_reporting()), &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, ClientLoadReportingWithDropTest,
- ::testing::Values(TestType().set_enable_load_reporting()), &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, FaultInjectionTest,
- ::testing::Values(
- TestType(), TestType().set_enable_rds_testing(),
- TestType().set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride),
- TestType().set_enable_rds_testing().set_filter_config_setup(
- TestType::FilterConfigSetup::kRouteOverride)),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, BootstrapSourceTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType().set_bootstrap_source(TestType::kBootstrapFromFile)),
- &TestTypeName);
- #ifndef DISABLED_XDS_PROTO_IN_CC
- // Run CSDS tests with RDS enabled and disabled.
- // These need to run with the bootstrap from an env var instead of from
- // a channel arg, since there needs to be a global XdsClient instance.
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, ClientStatusDiscoveryServiceTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_rds_testing(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_csds_streaming(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_rds_testing()
- .set_use_csds_streaming()),
- &TestTypeName);
- INSTANTIATE_TEST_SUITE_P(
- XdsTest, CsdsShortAdsTimeoutTest,
- ::testing::Values(
- TestType().set_bootstrap_source(TestType::kBootstrapFromEnvVar),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_rds_testing(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_use_csds_streaming(),
- TestType()
- .set_bootstrap_source(TestType::kBootstrapFromEnvVar)
- .set_enable_rds_testing()
- .set_use_csds_streaming()),
- &TestTypeName);
- #endif // DISABLED_XDS_PROTO_IN_CC
- } // namespace
- } // namespace testing
- } // namespace grpc
- int main(int argc, char** argv) {
- grpc::testing::TestEnvironment env(argc, argv);
- ::testing::InitGoogleTest(&argc, argv);
- // Make the backup poller poll very frequently in order to pick up
- // updates from all the subchannels's FDs.
- GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1);
- #if TARGET_OS_IPHONE
- // Workaround Apple CFStream bug
- gpr_setenv("grpc_cfstream", "0");
- #endif
- grpc_core::CertificateProviderRegistry::RegisterCertificateProviderFactory(
- absl::make_unique<grpc::testing::FakeCertificateProviderFactory>(
- "fake1", &grpc::testing::g_fake1_cert_data_map));
- grpc_core::CertificateProviderRegistry::RegisterCertificateProviderFactory(
- absl::make_unique<grpc::testing::FakeCertificateProviderFactory>(
- "fake2", &grpc::testing::g_fake2_cert_data_map));
- grpc_init();
- grpc_core::XdsHttpFilterRegistry::RegisterFilter(
- absl::make_unique<grpc::testing::NoOpHttpFilter>(
- "grpc.testing.client_only_http_filter",
- /* supported_on_clients = */ true, /* supported_on_servers = */ false,
- /* is_terminal_filter */ false),
- {"grpc.testing.client_only_http_filter"});
- grpc_core::XdsHttpFilterRegistry::RegisterFilter(
- absl::make_unique<grpc::testing::NoOpHttpFilter>(
- "grpc.testing.server_only_http_filter",
- /* supported_on_clients = */ false, /* supported_on_servers = */ true,
- /* is_terminal_filter */ false),
- {"grpc.testing.server_only_http_filter"});
- grpc_core::XdsHttpFilterRegistry::RegisterFilter(
- absl::make_unique<grpc::testing::NoOpHttpFilter>(
- "grpc.testing.terminal_http_filter",
- /* supported_on_clients = */ true, /* supported_on_servers = */ true,
- /* is_terminal_filter */ true),
- {"grpc.testing.terminal_http_filter"});
- const auto result = RUN_ALL_TESTS();
- grpc_shutdown();
- return result;
- }
|