testlist.inc.php 187 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811
  1. <?php
  2. // Copyright (C) 2010-2017 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. /**
  19. * Core test list
  20. *
  21. * @copyright Copyright (C) 2010-2017 Combodo SARL
  22. * @license http://opensource.org/licenses/AGPL-3.0
  23. */
  24. class TestBeHappy extends TestHandler // TestFunctionInOut, TestBizModel...
  25. {
  26. static public function GetName()
  27. {
  28. return 'Be happy!';
  29. }
  30. static public function GetDescription()
  31. {
  32. return 'Sample test with success';
  33. }
  34. protected function DoExecute()
  35. {
  36. echo "<p>Am I happy?</p>";
  37. echo "<p>Yes, I am!</p>";
  38. }
  39. }
  40. class TestBeSad extends TestHandler
  41. {
  42. static public function GetName()
  43. {
  44. return 'Be sad...';
  45. }
  46. static public function GetDescription()
  47. {
  48. return 'Sample test with failure';
  49. }
  50. protected function DoExecute()
  51. {
  52. echo "Am I happy?";
  53. throw new Exception('jamais content');
  54. }
  55. }
  56. class TestSQLQuery extends TestScenarioOnDB
  57. {
  58. static public function GetName() {return 'SQLQuery';}
  59. static public function GetDescription() {return 'SQLQuery does not depend on the rest of the framework, therefore it makes sense to have a separate test framework for it';}
  60. static public function GetDBHost() {return 'localhost';}
  61. static public function GetDBUser() {return 'root';}
  62. static public function GetDBPwd() {return '';}
  63. static public function GetDBName() {return 'TestSQLQuery';}
  64. static public function GetDBSubName() {return 'taratata';}
  65. protected function DoPrepare()
  66. {
  67. parent::DoPrepare();
  68. cmdbSource::CreateTable('CREATE TABLE `myTable` (myKey INT(11) NOT NULL auto_increment, column1 VARCHAR(255), column2 VARCHAR(255), PRIMARY KEY (`myKey`)) ENGINE = '.MYSQL_ENGINE);
  69. cmdbSource::CreateTable('CREATE TABLE `myTable1` (myKey1 INT(11) NOT NULL auto_increment, column1_1 VARCHAR(255), column1_2 VARCHAR(255), PRIMARY KEY (`myKey1`)) ENGINE = '.MYSQL_ENGINE);
  70. cmdbSource::CreateTable('CREATE TABLE `myTable2` (myKey2 INT(11) NOT NULL auto_increment, column2_1 VARCHAR(255), column2_2 VARCHAR(255), PRIMARY KEY (`myKey2`)) ENGINE = '.MYSQL_ENGINE);
  71. }
  72. protected function DoExecute()
  73. {
  74. $oQuery = new SQLObjectQuery(
  75. $sTable = 'myTable',
  76. $sTableAlias = 'myTableAlias',
  77. $aFields = array('column1'=>new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')),
  78. // $aFullTextNeedles = array('column1'),
  79. $bToDelete = false,
  80. $aValues = array()
  81. );
  82. $oQuery->AddCondition(Expression::FromOQL('DATE(NOW() - 1200 * 2) > \'2008-07-31\''));
  83. $oSubQuery1 = new SQLObjectQuery(
  84. $sTable = 'myTable1',
  85. $sTableAlias = 'myTable1Alias',
  86. $aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')),
  87. // $aFullTextNeedles = array(),
  88. $bToDelete = false,
  89. $aValues = array()
  90. );
  91. $oSubQuery2 = new SQLObjectQuery(
  92. $sTable = 'myTable2',
  93. $sTableAlias = 'myTable2Alias',
  94. $aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')),
  95. // $aFullTextNeedles = array(),
  96. $bToDelete = false,
  97. $aValues = array()
  98. );
  99. $oQuery->AddInnerJoin($oSubQuery1, 'column1', 'column1_1');
  100. $oQuery->AddLeftJoin($oSubQuery2, 'column2', 'column2_2');
  101. $oQuery->DisplayHtml();
  102. $oQuery->RenderDelete();
  103. $oQuery->RenderUpdate();
  104. echo '<p>'.$oQuery->RenderSelect().'</p>';
  105. $oQuery->RenderSelect(array('column1'));
  106. $oQuery->RenderSelect(array('column1', 'column2'));
  107. }
  108. }
  109. class TestOQLParser extends TestFunction
  110. {
  111. static public function GetName() {return 'Check OQL parsing';}
  112. static public function GetDescription() {return 'Attempts a series of queries, and in particular those with a bad syntax';}
  113. protected function CheckQuery($sQuery, $bIsCorrectQuery)
  114. {
  115. $oOql = new OqlInterpreter($sQuery);
  116. try
  117. {
  118. $oTrash = $oOql->Parse(); // Not expecting a given format, otherwise use ParseExpression/ParseObjectQuery/ParseValueSetQuery
  119. self::DumpVariable($oTrash);
  120. }
  121. catch (OQLException $OqlException)
  122. {
  123. if ($bIsCorrectQuery)
  124. {
  125. echo "<p>More info on this unexpected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  126. throw $OqlException;
  127. return false;
  128. }
  129. else
  130. {
  131. // Everything is fine :-)
  132. echo "<p>More info on this expected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  133. return true;
  134. }
  135. }
  136. catch (Exception $e)
  137. {
  138. if ($bIsCorrectQuery)
  139. {
  140. echo "<p>More info on this <b>un</b>expected failure:<br/>".htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8')."</p>\n";
  141. throw $OqlException;
  142. return false;
  143. }
  144. else
  145. {
  146. // Everything is fine :-)
  147. echo "<p>More info on this expected failure:<br/>".htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8')."</p>\n";
  148. return true;
  149. }
  150. }
  151. // The query was correctly parsed, was it expected to be correct ?
  152. if ($bIsCorrectQuery)
  153. {
  154. return true;
  155. }
  156. else
  157. {
  158. throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
  159. return false;
  160. }
  161. }
  162. protected function TestQuery($sQuery, $bIsCorrectQuery)
  163. {
  164. if (!$this->CheckQuery($sQuery, $bIsCorrectQuery))
  165. {
  166. return false;
  167. }
  168. return true;
  169. }
  170. public function DoExecute()
  171. {
  172. $aQueries = array(
  173. 'SELECT toto' => true,
  174. 'SELECT toto WHERE toto.a = 1' => true,
  175. 'SELECT toto WHERE toto.a = -1' => true,
  176. 'SELECT toto WHERE toto.a = (1-1)' => true,
  177. 'SELECT toto WHERE toto.a = (-1+3)' => true,
  178. 'SELECT toto WHERE toto.a = (3+-1)' => true,
  179. 'SELECT toto WHERE toto.a = (3--1)' => true,
  180. 'SELECT toto WHERE toto.a = (3++1)' => false,
  181. 'SELECT toto WHERE toto.a = 0xC' => true,
  182. 'SELECT toto WHERE toto.a = \'AXDVFS0xCZ32\'' => true,
  183. 'SELECT toto WHERE toto.a = :myparameter' => true,
  184. 'SELECT toto WHERE toto.a IN (:param1)' => true,
  185. 'SELECT toto WHERE toto.a IN (:param1, :param2)' => true,
  186. 'SELECT toto WHERE toto.a=1' => true,
  187. 'SELECT toto WHERE toto.a = "1"' => true,
  188. 'SELECT toto WHHHERE toto.a = "1"' => false,
  189. 'SELECT toto WHERE toto.a == "1"' => false,
  190. 'SELECT toto WHERE toto.a % 1' => false,
  191. 'SELECT toto WHERE toto.a & 1' => true, // bitwise and
  192. 'SELECT toto WHERE toto.a | 1' => true, // bitwise or
  193. 'SELECT toto WHERE toto.a ^ 1' => true, // bitwise xor
  194. 'SELECT toto WHERE toto.a << 1' => true, // bitwise left shift
  195. 'SELECT toto WHERE toto.a >> 1' => true, // bitwise right shift
  196. //'SELECT toto WHERE toto.a LIKE 1' => false,
  197. 'SELECT toto WHERE toto.a like \'arg\'' => false,
  198. 'SELECT toto WHERE toto.a NOT LIKE "That\'s it"' => true,
  199. 'SELECT toto WHERE toto.a NOT LIKE "That\'s "it""' => false,
  200. 'SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""' => true,
  201. 'SELECT toto WHERE toto.a NOT LIKE \'That"s it\'' => true,
  202. 'SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'' => false,
  203. 'SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\'' => true,
  204. 'SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"' => false,
  205. 'SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"' => true,
  206. 'SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'' => false,
  207. 'SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\'' => true,
  208. 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
  209. 'SELECT toto WHERE toto.a NOT LIKE "\\""' => true,
  210. 'SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"' => true,
  211. 'SELECT toto WHERE toto.a NOT LIKE "\\\\\\""' => true,
  212. 'SELECT toto WHERE toto.a NOT LIKE ""' => true,
  213. 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
  214. "SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = 'lnkContactRealObject' AND UserRightsMatrixClassGrant.action = 'modify' AND UserRightsMatrixClassGrant.login = 'Denis'" => true,
  215. "SELECT A WHERE A.col1 = 'lit1' AND A.col2 = 'lit2' AND A.col3 = 'lit3'" => true,
  216. 'SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"' => true,
  217. //'SELECT toto WHERE toto.a > \'asd\'' => false,
  218. 'SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345' => true,
  219. 'SELECT Device JOIN Site ON Device.site = Site.id' => true,
  220. 'SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true,
  221. "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = 123 AND B.col1 = 'aa') OR (A.col3 = 'zzz' AND B.col4 > 100)" => true,
  222. "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = B.col2 AND B.col1 = A.col2) OR (A.col3 = '' AND B.col4 > 100)" => true,
  223. "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2" => true,
  224. "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2" => true,
  225. "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2" => true,
  226. "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 & B.col2) = A.col2" => true,
  227. 'SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"' => true,
  228. // Several objects in a row...
  229. //
  230. 'SELECT A FROM A' => true,
  231. 'SELECT A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  232. 'SELECT A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  233. 'SELECT B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  234. 'SELECT A,B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  235. 'SELECT A, B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  236. 'SELECT B,A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  237. 'SELECT A, B,C FROM A JOIN B ON A.myB = B.id' => true,
  238. 'SELECT C FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  239. 'SELECT A JOIN B ON A.myB BELOW B.id WHERE A.col1 = 2' => true,
  240. 'SELECT A JOIN B ON B.myA BELOW A.id WHERE A.col1 = 2' => true,
  241. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id BELOW B.id WHERE A.col1 = 2 AND B.id = 3' => true,
  242. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id BELOW STRICT B.id WHERE A.col1 = 2 AND B.id = 3' => true,
  243. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW B.id WHERE A.col1 = 2 AND B.id = 3' => true,
  244. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW STRICT B.id WHERE A.col1 = 2 AND B.id = 3' => true,
  245. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id = B.id WHERE A.col1 BELOW 2 AND B.id = 3' => false,
  246. // Unions
  247. //
  248. 'SELECT A UNION SELECT B' => true,
  249. 'SELECT A WHERE A.b = "sdf" UNION SELECT B WHERE B.a = "sfde"' => true,
  250. 'SELECT A UNION SELECT B UNION SELECT C' => true,
  251. 'SELECT A UNION SELECT B UNION SELECT C UNION SELECT D' => true,
  252. 'SELECT A JOIN B ON A.myB = B.id JOIN C ON C.parent_id NOT BELOW B.id WHERE A.col1 = 2 AND B.id = 3 UNION SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true,
  253. );
  254. $iErrors = 0;
  255. foreach($aQueries as $sQuery => $bIsCorrectQuery)
  256. {
  257. $sIsOk = $bIsCorrectQuery ? 'good' : 'bad';
  258. echo "<h4>Testing query: $sQuery ($sIsOk)</h4>\n";
  259. try
  260. {
  261. $bRet = $this->TestQuery($sQuery, $bIsCorrectQuery);
  262. }
  263. catch(Exception $e)
  264. {
  265. $this->m_aErrors[] = $e->getMessage();
  266. $bRet = false;
  267. }
  268. if (!$bRet) $iErrors++;
  269. }
  270. return ($iErrors == 0);
  271. }
  272. }
  273. class TestOQLNormalization extends TestBizModel
  274. {
  275. static public function GetName() {return 'Check OQL normalization';}
  276. static public function GetDescription() {return 'Attempts a series of queries, and in particular those with unknown or inconsistent class/attributes. Assumes a very standard installation!';}
  277. protected function CheckQuery($sQuery, $bIsCorrectQuery)
  278. {
  279. try
  280. {
  281. $oSearch = DBObjectSearch::FromOQL($sQuery);
  282. self::DumpVariable($sQuery);
  283. }
  284. catch (OQLNormalizeException $OqlException)
  285. {
  286. if ($bIsCorrectQuery)
  287. {
  288. echo "<p>More info on this unexpected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  289. throw $OqlException;
  290. return false;
  291. }
  292. else
  293. {
  294. // Everything is fine :-)
  295. echo "<p>More info on this expected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  296. return true;
  297. }
  298. }
  299. catch (Exception $e)
  300. {
  301. if ($bIsCorrectQuery)
  302. {
  303. echo "<p>More info on this <b>un</b>expected failure:<br/>".htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8')."</p>\n";
  304. throw $e;
  305. return false;
  306. }
  307. else
  308. {
  309. // Everything is fine :-)
  310. echo "<p>More info on this expected failure:<br/>".htmlentities($e->getMessage(), ENT_QUOTES, 'UTF-8')."</p>\n";
  311. return true;
  312. }
  313. }
  314. // The query was correctly parsed, was it expected to be correct ?
  315. if ($bIsCorrectQuery)
  316. {
  317. return true;
  318. }
  319. else
  320. {
  321. throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
  322. return false;
  323. }
  324. }
  325. protected function TestQuery($sQuery, $bIsCorrectQuery)
  326. {
  327. if (!$this->CheckQuery($sQuery, $bIsCorrectQuery))
  328. {
  329. return false;
  330. }
  331. return true;
  332. }
  333. public function DoExecute()
  334. {
  335. $aQueries = array(
  336. 'SELECT Contact' => true,
  337. 'SELECT Contact WHERE nom_de_famille = "foo"' => false,
  338. 'SELECT Contact AS c WHERE name = "foo"' => true,
  339. 'SELECT Contact AS c WHERE nom_de_famille = "foo"' => false,
  340. 'SELECT Contact AS c WHERE c.name = "foo"' => true,
  341. 'SELECT Contact AS c WHERE Contact.name = "foo"' => false,
  342. 'SELECT Contact AS c WHERE x.name = "foo"' => false,
  343. 'SELECT Organization AS child JOIN Organization AS root ON child.parent_id BELOW root.id' => true,
  344. 'SELECT Organization AS root JOIN Organization AS child ON child.parent_id BELOW root.id' => true,
  345. 'SELECT RelationProfessionnelle' => false,
  346. 'SELECT RelationProfessionnelle AS c WHERE name = "foo"' => false,
  347. // The first query is the base query altered only in one place in the subsequent queries
  348. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE p.name LIKE "foo"' => true,
  349. 'SELECT Person AS p JOIN lnkXXXXXXXXXXXX AS lnk ON lnk.person_id = p.id WHERE p.name LIKE "foo"' => false,
  350. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.person_id = p.id WHERE p.name LIKE "foo"' => false,
  351. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON person_id = p.id WHERE p.name LIKE "foo"' => false,
  352. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = id WHERE p.name LIKE "foo"' => false,
  353. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.role = p.id WHERE p.name LIKE "foo"' => false,
  354. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.team_id = p.id WHERE p.name LIKE "foo"' => false,
  355. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id BELOW p.id WHERE p.name LIKE "foo"' => false,
  356. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.org_id WHERE p.name LIKE "foo"' => false,
  357. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.id = lnk.person_id WHERE p.name LIKE "foo"' => false, // inverted the JOIN spec
  358. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE name LIKE "foo"' => true,
  359. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE x.name LIKE "foo"' => false,
  360. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE p.eman LIKE "foo"' => false,
  361. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE eman LIKE "foo"' => false,
  362. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id WHERE id = 1' => false,
  363. 'SELECT Person AS p JOIN lnkPersonToTeam AS lnk ON p.id = lnk.person_id WHERE p.name LIKE "foo"' => false,
  364. 'SELECT Person AS p JOIN Organization AS o ON p.org_id = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"' => true,
  365. 'SELECT Person AS p JOIN Organization AS o ON p.location_id = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"' => false,
  366. 'SELECT Person AS p JOIN Organization AS o ON p.name = o.id WHERE p.name LIKE "foo" AND o.name LIKE "land"' => false,
  367. 'SELECT Person AS p JOIN Organization AS o ON p.org_id = o.id JOIN Person AS p ON p.org_id = o.id' => false,
  368. 'SELECT Person JOIN Organization AS o ON Person.org_id = o.id JOIN Person ON Person.org_id = o.id' => false,
  369. 'SELECT Person AS p JOIN Location AS l ON p.location_id = l.id' => true,
  370. 'SELECT Person AS p JOIN Location AS l ON p.location_id BELOW l.id' => false,
  371. 'SELECT Person FROM Person JOIN Location ON Person.location_id = Location.id' => true,
  372. 'SELECT p FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => true,
  373. 'SELECT l FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => true,
  374. 'SELECT l, p FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => true,
  375. 'SELECT p, l FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => true,
  376. 'SELECT foo FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => false,
  377. 'SELECT p, foo FROM Person AS p JOIN Location AS l ON p.location_id = l.id' => false,
  378. // Joins based on AttributeObjectKey
  379. //
  380. 'SELECT Attachment AS a JOIN UserRequest AS r ON a.item_id = r.id' => true,
  381. 'SELECT UserRequest AS r JOIN Attachment AS a ON a.item_id = r.id' => true,
  382. );
  383. $iErrors = 0;
  384. foreach($aQueries as $sQuery => $bIsCorrectQuery)
  385. {
  386. $sIsOk = $bIsCorrectQuery ? 'good' : 'bad';
  387. echo "<h4>Testing query: $sQuery ($sIsOk)</h4>\n";
  388. try
  389. {
  390. $bRet = $this->TestQuery($sQuery, $bIsCorrectQuery);
  391. }
  392. catch(Exception $e)
  393. {
  394. $this->m_aErrors[] = $e->getMessage();
  395. $bRet = false;
  396. }
  397. if (!$bRet) $iErrors++;
  398. }
  399. return ($iErrors == 0);
  400. }
  401. }
  402. class TestCSVParser extends TestFunction
  403. {
  404. static public function GetName() {return 'Check CSV parsing';}
  405. static public function GetDescription() {return 'Loads a set of CSV data';}
  406. public function DoExecute()
  407. {
  408. $sDataFile = '?field1?;?field2?;?field3?
  409. ?a?;?b?;?c?
  410. a;b;c
  411. ? a ? ; ? b ? ; ? c ?
  412. a ; b ; c
  413. ??;??;??
  414. ;;
  415. ?a"?;?b?;?c?
  416. ?a1
  417. a2?;?b?;?c?
  418. ?a1,a2?;?b?;?c?
  419. ?a?;?b?;?c1,",c2
  420. ,c3?
  421. ?a?;?b?;?ouf !?
  422. Espace sur la fin ; 1234; e@taloc.com ';
  423. self::DumpVariable($sDataFile);
  424. $aExpectedResult = array(
  425. //array('field1', 'field2', 'field3'),
  426. array('a', 'b', 'c'),
  427. array('a', 'b', 'c'),
  428. array(' a ', ' b ', ' c '),
  429. array('a', 'b', 'c'),
  430. array('', '', ''),
  431. array('', '', ''),
  432. array('a"', 'b', 'c'),
  433. array("a1\na2", 'b', 'c'),
  434. array('a1,a2', 'b', 'c'),
  435. array('a', 'b', "c1,\",c2\n,c3"),
  436. array('a', 'b', 'ouf !'),
  437. array('Espace sur la fin', '1234', 'e@taloc.com'),
  438. );
  439. $oCSVParser = new CSVParser($sDataFile, ';', '?');
  440. $aData = $oCSVParser->ToArray(1, null, 0);
  441. $iIssues = 0;
  442. echo "<table border=\"1\">\n";
  443. foreach ($aData as $iRow => $aRow)
  444. {
  445. echo "<tr>\n";
  446. foreach ($aRow as $iCol => $sCell)
  447. {
  448. if (empty($sCell))
  449. {
  450. $sCellValue = '&nbsp;';
  451. }
  452. else
  453. {
  454. $sCellValue = htmlentities($sCell, ENT_QUOTES, 'UTF-8');
  455. }
  456. if (!isset($aExpectedResult[$iRow][$iCol]))
  457. {
  458. $iIssues++;
  459. $sCellValue = "<span style =\"color: red; background-color: grey;\">$sCellValue</span>";
  460. }
  461. elseif ($aExpectedResult[$iRow][$iCol] != $sCell)
  462. {
  463. $iIssues++;
  464. $sCellValue = "<span style =\"color: red; background-color: lightgrey;\">$sCellValue</span>, expecting '<span style =\"color: green; background-color: lightgrey;\">".$aExpectedResult[$iRow][$iCol]."</span>'";
  465. }
  466. echo "<td><pre>$sCellValue</pre></td>";
  467. }
  468. echo "</tr>\n";
  469. }
  470. echo "</table>\n";
  471. return ($iIssues > 0);
  472. }
  473. }
  474. class TestGenericItoMyModel extends TestBizModelGeneric
  475. {
  476. static public function GetName()
  477. {
  478. return 'Generic RO test on '.self::GetConfigFile();
  479. }
  480. static public function GetConfigFile() {return '/config-test-mymodel.php';}
  481. }
  482. class TestGenericItopBigModel extends TestBizModelGeneric
  483. {
  484. static public function GetName()
  485. {
  486. return 'Generic RO test on '.self::GetConfigFile();
  487. }
  488. static public function GetConfigFile() {return '/config-test-itopv06.php';}
  489. }
  490. class TestUserRightsMatrixItop extends TestUserRights
  491. {
  492. static public function GetName()
  493. {
  494. return 'User rights test on user rights matrix';
  495. }
  496. static public function GetDescription()
  497. {
  498. return 'blah blah blah';
  499. }
  500. public function DoPrepare()
  501. {
  502. parent::DoPrepare();
  503. MetaModel::Startup('../config-test-itopv06.php');
  504. }
  505. protected function DoExecute()
  506. {
  507. $sUser = 'Romain';
  508. echo "<p>Totor: ".(UserRights::CheckCredentials('Totor', 'toto') ? 'ok' : 'NO')."</p>\n";
  509. echo "<p>Romain: ".(UserRights::CheckCredentials('Romain', 'toto') ? 'ok' : 'NO')."</p>\n";
  510. echo "<p>User: ".UserRights::GetUser()."</p>\n";
  511. echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
  512. echo "<p>Denis (impersonate) : ".(UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO')."</p>\n";
  513. echo "<p>User: ".UserRights::GetUser()."</p>\n";
  514. echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
  515. $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization"));
  516. echo "<p>IsActionAllowed...".(UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  517. echo "<p>IsStimulusAllowed...".(UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  518. echo "<p>IsActionAllowedOnAttribute...".(UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  519. return true;
  520. }
  521. }
  522. ///////////////////////////////////////////////////////////////////////////
  523. // Test a complex biz model on the fly
  524. ///////////////////////////////////////////////////////////////////////////
  525. class TestMyBizModel extends TestBizModel
  526. {
  527. static public function GetName()
  528. {
  529. return 'A series of tests on a weird business model';
  530. }
  531. static public function GetDescription()
  532. {
  533. return 'Attempts various operations and build complex queries';
  534. }
  535. static public function GetConfigFile() {return '/config-test-mymodel.php';}
  536. function test_linksinfo()
  537. {
  538. echo "<h4>Enum links</h4>";
  539. self::DumpVariable(MetaModel::EnumReferencedClasses("cmdbTeam"));
  540. self::DumpVariable(MetaModel::EnumReferencingClasses("Organization"));
  541. self::DumpVariable(MetaModel::EnumLinkingClasses());
  542. self::DumpVariable(MetaModel::EnumLinkingClasses("cmdbContact"));
  543. self::DumpVariable(MetaModel::EnumLinkingClasses("cmdWorkshop"));
  544. self::DumpVariable(MetaModel::GetLinkLabel("Liens_entre_contacts_et_workshop", "toworkshop"));
  545. }
  546. function test_list_attributes()
  547. {
  548. echo "<h4>List attributes</h4>";
  549. foreach(MetaModel::ListAttributeDefs("cmdbTeam") as $sAttCode=>$oAttDef)
  550. {
  551. echo $oAttDef->GetLabel()." / ".$oAttDef->GetDescription()." / ".$oAttDef->GetType()."</br>\n";
  552. }
  553. }
  554. function test_search()
  555. {
  556. echo "<h4>Two searches</h4>";
  557. $oFilterAllDevs = new DBObjectSearch("cmdbTeam");
  558. $oAllDevs = new DBObjectSet($oFilterAllDevs);
  559. echo "Found ".$oAllDevs->Count()." items.</br>\n";
  560. while ($oDev = $oAllDevs->Fetch())
  561. {
  562. $aValues = array();
  563. foreach(MetaModel::GetAttributesList($oAllDevs->GetClass()) as $sAttCode)
  564. {
  565. $aValues[] = MetaModel::GetLabel(get_class($oDev), $sAttCode)." (".MetaModel::GetDescription(get_class($oDev), $sAttCode).") = ".$oDev->GetAsHTML($sAttCode);
  566. }
  567. echo $oDev->GetKey()." => ".implode(", ", $aValues)."</br>\n";
  568. }
  569. // a second one
  570. $oMyFilter = new DBObjectSearch("cmdbContact");
  571. //$oMyFilter->AddCondition("name", "aii", "Finishes with");
  572. $oMyFilter->AddCondition("name", "aii");
  573. $this->search_and_show_list($oMyFilter);
  574. }
  575. function test_reload()
  576. {
  577. echo "<h4>Reload</h4>";
  578. $team = MetaModel::GetObject("cmdbContact", "2");
  579. echo "Chargement de l'attribut headcount: {$team->Get("headcount")}</br>\n";
  580. self::DumpVariable($team);
  581. }
  582. function test_setattribute()
  583. {
  584. echo "<h4>Set attribute and update</h4>";
  585. $team = MetaModel::GetObject("cmdbTeam", "2");
  586. $team->Set("headcount", rand(1,1000));
  587. $team->Set("email", "Luis ".rand(9,250));
  588. self::DumpVariable($team->ListChanges());
  589. echo "New headcount = {$team->Get("headcount")}</br>\n";
  590. echo "Computed name = {$team->Get("name")}</br>\n";
  591. $oMyChange = MetaModel::NewObject("CMDBChange");
  592. $oMyChange->Set("date", time());
  593. $oMyChange->Set("userinfo", "test_setattribute / Made by robot #".rand(1,100));
  594. $iChangeId = $oMyChange->DBInsert();
  595. //DBSearch::StartDebugQuery();
  596. $team->DBUpdateTracked($oMyChange);
  597. //DBSearch::StopDebugQuery();
  598. echo "<h4>Check the modified team</h4>";
  599. $oTeam = MetaModel::GetObject("cmdbTeam", "2");
  600. self::DumpVariable($oTeam);
  601. }
  602. function test_newobject()
  603. {
  604. $oMyChange = MetaModel::NewObject("CMDBChange");
  605. $oMyChange->Set("date", time());
  606. $oMyChange->Set("userinfo", "test_newobject / Made by robot #".rand(1,100));
  607. $iChangeId = $oMyChange->DBInsert();
  608. echo "<h4>Create a new object (team)</h4>";
  609. $oNewTeam = MetaModel::NewObject("cmdbTeam");
  610. $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
  611. $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
  612. $oNewTeam->Set("email", null);
  613. $oNewTeam->Set("owner", "ITOP");
  614. $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
  615. $iId = $oNewTeam->DBInsertTracked($oMyChange);
  616. echo "Created new team: $iId</br>";
  617. echo "<h4>Delete team #$iId</h4>";
  618. $oTeam = MetaModel::GetObject("cmdbTeam", $iId);
  619. $oTeam->DBDeleteTracked($oMyChange);
  620. echo "Deleted team: $iId</br>";
  621. self::DumpVariable($oTeam);
  622. }
  623. function test_updatecolumn()
  624. {
  625. $oMyChange = MetaModel::NewObject("CMDBChange");
  626. $oMyChange->Set("date", time());
  627. $oMyChange->Set("userinfo", "test_updatecolumn / Made by robot #".rand(1,100));
  628. $iChangeId = $oMyChange->DBInsert();
  629. $sNewEmail = "updatecol".rand(9,250)."@quedlaballe.com";
  630. echo "<h4>Update a the email: set to '$sNewEmail'</h4>";
  631. $oMyFilter = new DBObjectSearch("cmdbContact");
  632. $oMyFilter->AddCondition("name", "o", "Contains");
  633. echo "Candidates before:</br>";
  634. $this->search_and_show_list($oMyFilter);
  635. MetaModel::BulkUpdateTracked($oMyChange, $oMyFilter, array("email" => $sNewEmail));
  636. echo "Candidates after:</br>";
  637. $this->search_and_show_list($oMyFilter);
  638. }
  639. function test_error()
  640. {
  641. trigger_error("Stop requested", E_USER_ERROR);
  642. }
  643. function test_changetracking()
  644. {
  645. echo "<h4>Create a change</h4>";
  646. $oMyChange = MetaModel::NewObject("CMDBChange");
  647. $oMyChange->Set("date", time());
  648. $oMyChange->Set("userinfo", "Made by robot #".rand(1,100));
  649. $iChangeId = $oMyChange->DBInsert();
  650. echo "Created new change: $iChangeId</br>";
  651. self::DumpVariable($oMyChange);
  652. echo "<h4>Create a new object (team)</h4>";
  653. $oNewTeam = MetaModel::NewObject("cmdbTeam");
  654. $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
  655. $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
  656. $oNewTeam->Set("email", null);
  657. $oNewTeam->Set("owner", "ITOP");
  658. $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
  659. $iId = $oNewTeam->DBInsertTracked($oMyChange);
  660. echo "Created new team: $iId</br>";
  661. echo "<h4>Delete team #$iId</h4>";
  662. $oTeam = MetaModel::GetObject("cmdbTeam", $iId);
  663. $oTeam->DBDeleteTracked($oMyChange);
  664. echo "Deleted team: $iId</br>";
  665. self::DumpVariable($oTeam);
  666. }
  667. function test_zlist()
  668. {
  669. echo "<h4>Test ZLists</h4>";
  670. $aZLists = MetaModel::EnumZLists();
  671. foreach ($aZLists as $sListCode)
  672. {
  673. $aListInfos = MetaModel::GetZListInfo($sListCode);
  674. echo "<h4>List '".$sListCode."' (".$aListInfos["description"].") of type '".$aListInfos["type"]."'</h5>\n";
  675. foreach (MetaModel::GetSubclasses("cmdbObjectHomeMade") as $sKlass)
  676. {
  677. $aItems = MetaModel::FlattenZlist(MetaModel::GetZListItems($sKlass, $sListCode));
  678. if (count($aItems) == 0) continue;
  679. echo "$sKlass - $sListCode : {".implode(", ", $aItems)."}</br>\n";
  680. }
  681. }
  682. echo "<h4>IsAttributeInZList()... </h4>";
  683. echo "Liens_entre_contacts_et_workshop::ws_info in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "ws_info") ? "yes" : "no")."</br>\n";
  684. echo "Liens_entre_contacts_et_workshop::toworkshop in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "toworkshop") ? "yes" : "no")."</br>\n";
  685. }
  686. function test_pkey()
  687. {
  688. echo "<h4>Test search on pkey</h4>";
  689. $sExpr1 = "SELECT cmdbContact WHERE id IN (40, 42)";
  690. $sExpr2 = "SELECT cmdbContact WHERE IN NOT IN (40, 42)";
  691. $this->search_and_show_list_from_oql($sExpr1);
  692. $this->search_and_show_list_from_oql($sExpr2);
  693. echo "Et maintenant, on fusionne....</br>\n";
  694. $oSet1 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr1));
  695. $oSet2 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr2));
  696. $oIntersect = $oSet1->CreateIntersect($oSet2);
  697. $oDelta = $oSet1->CreateDelta($oSet2);
  698. $oMerge = clone $oSet1;
  699. $oAppend->Append($oSet2);
  700. $oAppend->Append($oSet2);
  701. echo "Set1 - Found ".$oSet1->Count()." items.</br>\n";
  702. echo "Set2 - Found ".$oSet2->Count()." items.</br>\n";
  703. echo "Intersect - Found ".$oIntersect->Count()." items.</br>\n";
  704. echo "Delta - Found ".$oDelta->Count()." items.</br>\n";
  705. echo "Append - Found ".$oAppend->Count()." items.</br>\n";
  706. //$this->show_list($oObjSet);
  707. }
  708. function test_relations()
  709. {
  710. echo "<h4>Test relations</h4>";
  711. //self::DumpVariable(MetaModel::EnumRelationQueries("cmdbObjectHomeMade", "Potes"));
  712. self::DumpVariable(MetaModel::EnumRelationQueries("cmdbContact", "Potes"));
  713. $iMaxDepth = 9;
  714. echo "Max depth = $iMaxDepth</br>\n";
  715. $oObj = MetaModel::GetObject("cmdbContact", 18);
  716. $aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth);
  717. echo $oObj->Get('name')." has some 'Potes'...</br>\n";
  718. foreach ($aRels as $sClass => $aObjs)
  719. {
  720. echo "$sClass, count = ".count($aObjs)." =&gt; ".implode(', ', array_keys($aObjs))."</br>\n";
  721. $oObjectSet = CMDBObjectSet::FromArray($sClass, $aObjs);
  722. $this->show_list($oObjectSet);
  723. }
  724. echo "<h4>Test relations - same results, by the mean of a OQL</h4>";
  725. $this->search_and_show_list_from_oql("cmdbContact: RELATED (Potes, $iMaxDepth) TO (cmdbContact: pkey = 18)");
  726. }
  727. function test_linkedset()
  728. {
  729. echo "<h4>Linked set attributes</h4>\n";
  730. $oObj = MetaModel::GetObject("cmdbContact", 18);
  731. echo "<h5>Current workshops</h5>\n";
  732. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  733. $this->show_list($oSetWorkshopsCurr);
  734. echo "<h5>Setting workshops</h5>\n";
  735. $oNewLink = new cmdbLiens();
  736. $oNewLink->Set('toworkshop', 2);
  737. $oNewLink->Set('function', 'mafonctioooon');
  738. $oNewLink->Set('a1', 'tralala1');
  739. $oNewLink->Set('a2', 'F7M');
  740. $oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink));
  741. $oObj->Set("myworkshops", $oSetWorkshops);
  742. $this->show_list($oSetWorkshops);
  743. echo "<h5>New workshops</h5>\n";
  744. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  745. $this->show_list($oSetWorkshopsCurr);
  746. $oMyChange = MetaModel::NewObject("CMDBChange");
  747. $oMyChange->Set("date", time());
  748. $oMyChange->Set("userinfo", "test_linkedset / Made by robot #".rand(1,100));
  749. $iChangeId = $oMyChange->DBInsert();
  750. $oObj->DBUpdateTracked($oMyChange);
  751. $oObj = MetaModel::GetObject("cmdbContact", 18);
  752. echo "<h5>After the write</h5>\n";
  753. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  754. $this->show_list($oSetWorkshopsCurr);
  755. }
  756. function test_object_lifecycle()
  757. {
  758. echo "<h4>Test object lifecycle</h4>";
  759. self::DumpVariable(MetaModel::GetStateAttributeCode("cmdbContact"));
  760. self::DumpVariable(MetaModel::EnumStates("cmdbContact"));
  761. self::DumpVariable(MetaModel::EnumStimuli("cmdbContact"));
  762. foreach(MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef)
  763. {
  764. echo "<p>Transition from <strong>$sStateCode</strong></p>\n";
  765. self::DumpVariable(MetaModel::EnumTransitions("cmdbContact", $sStateCode));
  766. }
  767. $oObj = MetaModel::GetObject("cmdbContact", 18);
  768. echo "Current state: ".$oObj->GetState()."... let's go to school...";
  769. self::DumpVariable($oObj->EnumTransitions());
  770. $oObj->ApplyStimulus("toschool");
  771. echo "New state: ".$oObj->GetState()."... let's get older...";
  772. self::DumpVariable($oObj->EnumTransitions());
  773. $oObj->ApplyStimulus("raise");
  774. echo "New state: ".$oObj->GetState()."... let's try to go further... (should give an error)";
  775. self::DumpVariable($oObj->EnumTransitions());
  776. $oObj->ApplyStimulus("raise"); // should give an error
  777. }
  778. protected function DoExecute()
  779. {
  780. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  781. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  782. //$this->test_linksinfo();
  783. //$this->test_list_attributes();
  784. //$this->test_search();
  785. //$this->test_reload();
  786. //$this->test_newobject();
  787. $this->test_setattribute();
  788. //$this->test_updatecolumn();
  789. //$this->test_error();
  790. //$this->test_changetracking();
  791. $this->test_zlist();
  792. $this->test_OQL();
  793. //$this->test_pkey();
  794. $this->test_relations();
  795. $this->test_linkedset();
  796. $this->test_object_lifecycle();
  797. }
  798. }
  799. ///////////////////////////////////////////////////////////////////////////
  800. // Test a complex biz model on the fly
  801. ///////////////////////////////////////////////////////////////////////////
  802. abstract class MyFarm extends TestBizModel
  803. {
  804. static public function GetConfigFile() {return '/config-test-farm.php';}
  805. protected function DoPrepare()
  806. {
  807. parent::DoPrepare();
  808. $this->ResetDB();
  809. MetaModel::DBCheckIntegrity();
  810. }
  811. protected function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth)
  812. {
  813. $oNew = MetaModel::NewObject('Mammal');
  814. $oNew->Set('species', $sSpecies);
  815. $oNew->Set('sex', $sSex);
  816. $oNew->Set('speed', $iSpeed);
  817. $oNew->Set('mother', $iMotherid);
  818. $oNew->Set('father', $iFatherId);
  819. $oNew->Set('name', $sName);
  820. $oNew->Set('height', $iHeight);
  821. $oNew->Set('birth', $sBirth);
  822. return $this->ObjectToDB($oNew);
  823. }
  824. protected function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId)
  825. {
  826. $oNew = MetaModel::NewObject('Bird');
  827. $oNew->Set('species', $sSpecies);
  828. $oNew->Set('sex', $sSex);
  829. $oNew->Set('speed', $iSpeed);
  830. $oNew->Set('mother', $iMotherid);
  831. $oNew->Set('father', $iFatherId);
  832. return $this->ObjectToDB($oNew);
  833. }
  834. protected function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed)
  835. {
  836. $oNew = MetaModel::NewObject('FlyingBird');
  837. $oNew->Set('species', $sSpecies);
  838. $oNew->Set('sex', $sSex);
  839. $oNew->Set('speed', $iSpeed);
  840. $oNew->Set('mother', $iMotherid);
  841. $oNew->Set('father', $iFatherId);
  842. $oNew->Set('flyingspeed', $iFlyingSpeed);
  843. return $this->ObjectToDB($oNew);
  844. }
  845. private function InsertGroup($sName, $iLeaderId)
  846. {
  847. $oNew = MetaModel::NewObject('Group');
  848. $oNew->Set('name', $sName);
  849. $oNew->Set('leader', $iLeaderId);
  850. $iId = $oNew->DBInsertNoReload();
  851. return $iId;
  852. }
  853. }
  854. class TestQueriesOnFarm extends MyFarm
  855. {
  856. static public function GetName()
  857. {
  858. return 'Farm test';
  859. }
  860. static public function GetDescription()
  861. {
  862. return 'A series of tests on the farm business model (SQL generation)';
  863. }
  864. protected function CheckQuery($sQuery, $bIsCorrectQuery)
  865. {
  866. if ($bIsCorrectQuery)
  867. {
  868. echo "<h4 style=\"color:green;\">$sQuery</h4>\n";
  869. }
  870. else
  871. {
  872. echo "<h4 style=\"color:red;\">$sQuery</h3>\n";
  873. }
  874. try
  875. {
  876. //$oOql = new OqlInterpreter($sQuery);
  877. //$oTrash = $oOql->ParseQuery();
  878. //self::DumpVariable($oTrash, true);
  879. $oMyFilter = DBObjectSearch::FromOQL($sQuery);
  880. }
  881. catch (OQLException $oOqlException)
  882. {
  883. if ($bIsCorrectQuery)
  884. {
  885. echo "<p>More info on this unexpected failure:<br/>".$oOqlException->getHtmlDesc()."</p>\n";
  886. throw $oOqlException;
  887. return false;
  888. }
  889. else
  890. {
  891. // Everything is fine :-)
  892. echo "<p>More info on this expected failure:\n";
  893. echo "<ul>\n";
  894. echo "<li>".get_class($oOqlException)."</li>\n";
  895. echo "<li>".$oOqlException->getMessage()."</li>\n";
  896. echo "<li>".$oOqlException->getHtmlDesc()."</li>\n";
  897. echo "</ul>\n";
  898. echo "</p>\n";
  899. return true;
  900. }
  901. }
  902. // The query was correctly parsed, was it expected to be correct ?
  903. if (!$bIsCorrectQuery)
  904. {
  905. throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
  906. return false;
  907. }
  908. echo "<p>To OQL: ".$oMyFilter->ToOQL()."</p>";
  909. $this->search_and_show_list($oMyFilter);
  910. //echo "<p>first pass<p>\n";
  911. //self::DumpVariable($oMyFilter, true);
  912. $sQuery1 = $oMyFilter->MakeSelectQuery();
  913. //echo "<p>second pass<p>\n";
  914. //self::DumpVariable($oMyFilter, true);
  915. //$sQuery1 = $oMyFilter->MakeSelectQuery();
  916. $sSerialize = $oMyFilter->serialize();
  917. echo "<p>Serialized:$sSerialize</p>\n";
  918. $oFilter2 = DBObjectSearch::unserialize($sSerialize);
  919. try
  920. {
  921. $sQuery2 = $oMyFilter2->MakeSelectQuery();
  922. }
  923. catch (Exception $e)
  924. {
  925. echo "<p>Could not compute the query after unserialize</p>\n";
  926. echo "<p>Query 1: $sQuery1</p>\n";
  927. MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
  928. throw $e;
  929. }
  930. //if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same!
  931. if ($sQuery1 != $sQuery2)
  932. {
  933. echo "<p>serialize/unserialize mismatch :-(</p>\n";
  934. MyHelpers::var_cmp_html($sQuery1, $sQuery2);
  935. MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
  936. return false;
  937. }
  938. return true;
  939. }
  940. protected function DoExecute()
  941. {
  942. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  943. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  944. echo "<h3>Create protagonists...</h3>";
  945. $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
  946. $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
  947. $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
  948. $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
  949. $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
  950. $this->InsertBird('rooster', 'male', 12, 0, 0);
  951. $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
  952. // Benchmarking
  953. //
  954. if (false)
  955. {
  956. define ('COUNT_BENCHMARK', 10);
  957. echo "<h3>Parsing a long query, ".COUNT_BENCHMARK." times</h3>";
  958. $sQuery = "SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR) AND Dad.height * 2 <= ROUND(TO_DAYS(Dad.birth) / (3 + 1) * 5 - 3)";
  959. $fStart = MyHelpers::getmicrotime();
  960. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  961. {
  962. $oMyFilter = DBObjectSearch::FromOQL($sQuery);
  963. }
  964. $fDuration = MyHelpers::getmicrotime() - $fStart;
  965. $fParsingDuration = $fDuration / COUNT_BENCHMARK;
  966. echo "<p>Mean time by op: $fParsingDuration</p>";
  967. }
  968. echo "<h3>Test queries...</h3>";
  969. $aQueries = array(
  970. 'SELECT Animal' => true,
  971. 'SELECT Animal WHERE Animal.pkey = 1' => false,
  972. 'SELECT Animal WHERE Animal.id = 1' => true,
  973. 'SELECT Aniiimal' => false,
  974. 'SELECTe Animal' => false,
  975. 'SELECT * FROM Animal' => false,
  976. 'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true,
  977. 'SELECT Animal AS zoo WHERE species = \'human\'' => true,
  978. 'SELECT Animal AS zoo WHERE espece = \'human\'' => false,
  979. 'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true,
  980. 'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false,
  981. 'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true,
  982. 'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true,
  983. 'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false,
  984. 'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true,
  985. 'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true,
  986. 'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true,
  987. 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
  988. 'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true,
  989. 'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true,
  990. 'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true,
  991. 'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true,
  992. 'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true,
  993. 'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true,
  994. 'SELECT Mammal AS m WHERE (1 + 2' => false,
  995. 'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true,
  996. 'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true,
  997. 'SELECT Mammal AS m WHERE 1/0' => true,
  998. 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
  999. 'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true,
  1000. 'SELECT Group JOIN Animal ON Group.leader = Animal.id' => true,
  1001. 'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true,
  1002. 'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false,
  1003. 'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false,
  1004. 'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false,
  1005. 'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false,
  1006. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false,
  1007. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true,
  1008. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true,
  1009. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false,
  1010. 'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false,
  1011. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true,
  1012. 'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false,
  1013. 'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false,
  1014. 'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false,
  1015. 'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true,
  1016. 'SELECT Group AS G WHERE G.leader_speed < 100000' => true,
  1017. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
  1018. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true,
  1019. 'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  1020. 'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
  1021. 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  1022. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
  1023. 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true,
  1024. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
  1025. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.id = 1' => true,
  1026. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => false,
  1027. 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  1028. 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.speed = 0' => true,
  1029. 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
  1030. 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true,
  1031. 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id JOIN Mammal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.name=\'chloe\' OR Child.name=\'bizounours\'' => true,
  1032. // Specifying multiple objects
  1033. 'SELECT Animal FROM Animal' => true,
  1034. 'SELECT yelele FROM Animal' => false,
  1035. 'SELECT Animal FROM Animal AS A' => false,
  1036. 'SELECT A FROM Animal AS A' => true,
  1037. );
  1038. //$aQueries = array(
  1039. // 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
  1040. //);
  1041. foreach($aQueries as $sQuery => $bIsCorrect)
  1042. {
  1043. $this->CheckQuery($sQuery, $bIsCorrect);
  1044. }
  1045. return true;
  1046. }
  1047. }
  1048. ///////////////////////////////////////////////////////////////////////////
  1049. // Test data load
  1050. ///////////////////////////////////////////////////////////////////////////
  1051. class TestBulkChangeOnFarm extends TestBizModel
  1052. {
  1053. static public function GetName()
  1054. {
  1055. return 'Farm test - data load';
  1056. }
  1057. static public function GetDescription()
  1058. {
  1059. return 'Bulk load';
  1060. }
  1061. static public function GetConfigFile() {return '/config-test-farm.php';}
  1062. protected function DoPrepare()
  1063. {
  1064. parent::DoPrepare();
  1065. $this->ResetDB();
  1066. MetaModel::DBCheckIntegrity();
  1067. }
  1068. protected function DoExecute()
  1069. {
  1070. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  1071. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  1072. $oParser = new CSVParser("denomination,hauteur,age
  1073. suzy,123,2009-01-01
  1074. chita,456,
  1075. ", ',', '"');
  1076. $aData = $oParser->ToArray(1, array('_name', '_height', '_birth'));
  1077. self::DumpVariable($aData);
  1078. $oBulk = new BulkChange(
  1079. 'Mammal',
  1080. $aData,
  1081. // attributes
  1082. array('name' => '_name', 'height' => '_height', 'birth' => '_birth'),
  1083. // ext keys
  1084. array(),
  1085. // reconciliation
  1086. array('name')
  1087. );
  1088. $oMyChange = MetaModel::NewObject("CMDBChange");
  1089. $oMyChange->Set("date", time());
  1090. $oMyChange->Set("userinfo", "Testor");
  1091. $iChangeId = $oMyChange->DBInsert();
  1092. // echo "Created new change: $iChangeId</br>";
  1093. echo "<h3>Planned for loading...</h3>";
  1094. $aRes = $oBulk->Process();
  1095. self::DumpVariable($aRes);
  1096. echo "<h3>Go for loading...</h3>";
  1097. $aRes = $oBulk->Process($oMyChange);
  1098. self::DumpVariable($aRes);
  1099. return;
  1100. $oRawData = array(
  1101. 'Mammal',
  1102. array('species', 'sex', 'speed', 'mother', 'father', 'name', 'height', 'birth'),
  1103. "human,male,23,0,0,romulus,192,1971
  1104. human,male,23,0,0,remus,154,-50
  1105. human,male,23,0,0,julius,160,-49
  1106. human,female,23,0,0,cleopatra,142,-50
  1107. pig,female,23,0,0,confucius,50,2003"
  1108. );
  1109. }
  1110. }
  1111. ///////////////////////////////////////////////////////////////////////////
  1112. // Test data load
  1113. ///////////////////////////////////////////////////////////////////////////
  1114. class TestFullTextSearchOnFarm extends MyFarm
  1115. {
  1116. static public function GetName()
  1117. {
  1118. return 'Farm test - full text search';
  1119. }
  1120. static public function GetDescription()
  1121. {
  1122. return 'Focus on the full text search feature';
  1123. }
  1124. protected function DoExecute()
  1125. {
  1126. echo "<h3>Create protagonists...</h3>";
  1127. $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
  1128. $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
  1129. $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
  1130. $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
  1131. $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
  1132. $this->InsertBird('rooster', 'male', 12, 0, 0);
  1133. $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
  1134. echo "<h3>Search...</h3>";
  1135. $oSearch = new DBObjectSearch('Mammal');
  1136. $oSearch->AddCondition_FullText('manof');
  1137. //$oResultSet = new DBObjectSet($oSearch);
  1138. $this->search_and_show_list($oSearch);
  1139. }
  1140. }
  1141. ///////////////////////////////////////////////////////////////////////////
  1142. // Test queries
  1143. ///////////////////////////////////////////////////////////////////////////
  1144. class TestItopEfficiency extends TestBizModel
  1145. {
  1146. static public function GetName()
  1147. {
  1148. return 'Itop - benchmark';
  1149. }
  1150. static public function GetDescription()
  1151. {
  1152. return 'Measure time to perform the queries';
  1153. }
  1154. protected function DoBenchmark($sOqlQuery)
  1155. {
  1156. echo "<h3>Testing query: $sOqlQuery</h3>";
  1157. $fStart = MyHelpers::getmicrotime();
  1158. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  1159. {
  1160. $oFilter = DBObjectSearch::FromOQL($sOqlQuery);
  1161. }
  1162. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1163. $fParsingDuration = $fDuration / COUNT_BENCHMARK;
  1164. $fStart = MyHelpers::getmicrotime();
  1165. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  1166. {
  1167. $sSQL = $oFilter->MakeSelectQuery();
  1168. }
  1169. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1170. $fBuildDuration = $fDuration / COUNT_BENCHMARK;
  1171. $fStart = MyHelpers::getmicrotime();
  1172. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  1173. {
  1174. $res = CMDBSource::Query($sSQL);
  1175. }
  1176. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1177. $fQueryDuration = $fDuration / COUNT_BENCHMARK;
  1178. // The fetch could not be repeated with the same results
  1179. // But we've seen so far that is was very very quick to exec
  1180. // So it makes sense to benchmark it a single time
  1181. $fStart = MyHelpers::getmicrotime();
  1182. $aRow = CMDBSource::FetchArray($res);
  1183. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1184. $fFetchDuration = $fDuration;
  1185. $fStart = MyHelpers::getmicrotime();
  1186. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  1187. {
  1188. $sOql = $oFilter->ToOQL();
  1189. }
  1190. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1191. $fToOqlDuration = $fDuration / COUNT_BENCHMARK;
  1192. echo "<ul>\n";
  1193. echo "<li>Parsing: $fParsingDuration</li>\n";
  1194. echo "<li>Build: $fBuildDuration</li>\n";
  1195. echo "<li>Query: $fQueryDuration</li>\n";
  1196. echo "<li>Fetch: $fFetchDuration</li>\n";
  1197. echo "<li>ToOql: $fToOqlDuration</li>\n";
  1198. echo "</ul>\n";
  1199. // Everything but the ToOQL (wich is interesting, anyhow)
  1200. $fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration;
  1201. if ($fTotal == 0)
  1202. {
  1203. $aRet = array(
  1204. 'rows' => CMDBSource::NbRows($res),
  1205. 'duration (s)' => '0 (negligeable)',
  1206. 'parsing (%)' => '?',
  1207. 'build SQL (%)' => '?',
  1208. 'query exec (%)' => '?',
  1209. 'fetch (%)' => '?',
  1210. 'to OQL (%)' => '?',
  1211. 'parsing+build (%)' => '?',
  1212. );
  1213. }
  1214. else
  1215. {
  1216. $aRet = array(
  1217. 'rows' => CMDBSource::NbRows($res),
  1218. 'duration (s)' => round($fTotal, 4),
  1219. 'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
  1220. 'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
  1221. 'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
  1222. 'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
  1223. 'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
  1224. 'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
  1225. );
  1226. }
  1227. return $aRet;
  1228. }
  1229. protected function DoExecute()
  1230. {
  1231. define ('COUNT_BENCHMARK', 3);
  1232. echo "<p>The test will be repeated ".COUNT_BENCHMARK." times</p>";
  1233. $aQueries = array(
  1234. 'SELECT CMDBChangeOpSetAttribute',
  1235. 'SELECT CMDBChangeOpSetAttribute WHERE id=10',
  1236. 'SELECT CMDBChangeOpSetAttribute WHERE id=123456789',
  1237. 'SELECT CMDBChangeOpSetAttribute WHERE CMDBChangeOpSetAttribute.id=10',
  1238. 'SELECT Ticket',
  1239. 'SELECT Ticket WHERE id=1',
  1240. 'SELECT Person',
  1241. 'SELECT Person WHERE id=1',
  1242. 'SELECT Server',
  1243. 'SELECT Server WHERE id=1',
  1244. 'SELECT UserRequest JOIN Person ON UserRequest.agent_id = Person.id WHERE Person.id = 5',
  1245. );
  1246. $aStats = array();
  1247. foreach ($aQueries as $sOQL)
  1248. {
  1249. $aStats[$sOQL] = $this->DoBenchmark($sOQL);
  1250. }
  1251. $aData = array();
  1252. foreach ($aStats as $sOQL => $aResults)
  1253. {
  1254. $aValues = array();
  1255. $aValues['OQL'] = htmlentities($sOQL, ENT_QUOTES, 'UTF-8');
  1256. foreach($aResults as $sDesc => $sInfo)
  1257. {
  1258. $aValues[$sDesc] = htmlentities($sInfo, ENT_QUOTES, 'UTF-8');
  1259. }
  1260. $aData[] = $aValues;
  1261. }
  1262. echo MyHelpers::make_table_from_assoc_array($aData);
  1263. }
  1264. }
  1265. ///////////////////////////////////////////////////////////////////////////
  1266. // Benchmark queries
  1267. ///////////////////////////////////////////////////////////////////////////
  1268. class TestQueries extends TestBizModel
  1269. {
  1270. static public function GetName()
  1271. {
  1272. return 'Itop - queries';
  1273. }
  1274. static public function GetDescription()
  1275. {
  1276. return 'Try as many queries as possible';
  1277. }
  1278. protected function DoBenchmark($sOqlQuery)
  1279. {
  1280. echo "<h5>Testing query: $sOqlQuery</h5>";
  1281. $fStart = MyHelpers::getmicrotime();
  1282. $oFilter = DBObjectSearch::FromOQL($sOqlQuery);
  1283. $fParsingDuration = MyHelpers::getmicrotime() - $fStart;
  1284. $fStart = MyHelpers::getmicrotime();
  1285. $sSQL = $oFilter->MakeSelectQuery();
  1286. $fBuildDuration = MyHelpers::getmicrotime() - $fStart;
  1287. $fStart = MyHelpers::getmicrotime();
  1288. $res = CMDBSource::Query($sSQL);
  1289. $fQueryDuration = MyHelpers::getmicrotime() - $fStart;
  1290. // The fetch could not be repeated with the same results
  1291. // But we've seen so far that is was very very quick to exec
  1292. // So it makes sense to benchmark it a single time
  1293. $fStart = MyHelpers::getmicrotime();
  1294. $aRow = CMDBSource::FetchArray($res);
  1295. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1296. $fFetchDuration = $fDuration;
  1297. $fStart = MyHelpers::getmicrotime();
  1298. $sOql = $oFilter->ToOQL();
  1299. $fToOqlDuration = MyHelpers::getmicrotime() - $fStart;
  1300. if (false)
  1301. {
  1302. echo "<ul style=\"font-size:smaller;\">\n";
  1303. echo "<li>Parsing: $fParsingDuration</li>\n";
  1304. echo "<li>Build: $fBuildDuration</li>\n";
  1305. echo "<li>Query: $fQueryDuration</li>\n";
  1306. echo "<li>Fetch: $fFetchDuration</li>\n";
  1307. echo "<li>ToOql: $fToOqlDuration</li>\n";
  1308. echo "</ul>\n";
  1309. }
  1310. // Everything but the ToOQL (wich is interesting, anyhow)
  1311. $fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration;
  1312. if ($fTotal == 0)
  1313. {
  1314. $aRet = array(
  1315. 'rows' => CMDBSource::NbRows($res),
  1316. 'duration (s)' => '0 (negligeable)',
  1317. 'parsing (%)' => '?',
  1318. 'build SQL (%)' => '?',
  1319. 'query exec (%)' => '?',
  1320. 'fetch (%)' => '?',
  1321. 'to OQL (%)' => '?',
  1322. 'parsing+build (%)' => '?',
  1323. );
  1324. }
  1325. else
  1326. {
  1327. $aRet = array(
  1328. 'rows' => CMDBSource::NbRows($res),
  1329. 'duration (s)' => round($fTotal, 4),
  1330. 'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
  1331. 'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
  1332. 'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
  1333. 'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
  1334. 'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
  1335. 'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
  1336. );
  1337. }
  1338. return $aRet;
  1339. }
  1340. protected function DoExecute()
  1341. {
  1342. $aQueries = array(
  1343. 'SELECT Person AS PP WHERE PP.friendlyname LIKE "%dali"',
  1344. 'SELECT Person AS PP WHERE PP.location_id_friendlyname LIKE "%ce ch%"',
  1345. 'SELECT Organization AS OO JOIN Person AS PP ON PP.org_id = OO.id',
  1346. 'SELECT lnkPersonToTeam AS lnk JOIN Team AS T ON lnk.team_id = T.id',
  1347. 'SELECT lnkPersonToTeam AS lnk JOIN Team AS T ON lnk.team_id = T.id JOIN Person AS p ON lnk.person_id = p.id',
  1348. 'SELECT UserRequest AS ur JOIN Person ON ur.agent_id = Person.id WHERE Person.id = 5',
  1349. // this one is failing...
  1350. //'SELECT L, P FROM Person AS P JOIN Location AS L ON P.location_id = L.id',
  1351. );
  1352. foreach (MetaModel::GetClasses() as $sClass)
  1353. {
  1354. $aQueries[] = 'SELECT '.$sClass;
  1355. $aQueries[] = 'SELECT '.$sClass.' AS zz';
  1356. $aQueries[] = 'SELECT '.$sClass.' AS zz WHERE id = 1';
  1357. }
  1358. $aStats = array();
  1359. foreach ($aQueries as $sOQL)
  1360. {
  1361. $aStats[$sOQL] = $this->DoBenchmark($sOQL);
  1362. }
  1363. $aData = array();
  1364. foreach ($aStats as $sOQL => $aResults)
  1365. {
  1366. $aValues = array();
  1367. $aValues['OQL'] = htmlentities($sOQL, ENT_QUOTES, 'UTF-8');
  1368. foreach($aResults as $sDesc => $sInfo)
  1369. {
  1370. $aValues[$sDesc] = htmlentities($sInfo, ENT_QUOTES, 'UTF-8');
  1371. }
  1372. $aData[] = $aValues;
  1373. }
  1374. echo MyHelpers::make_table_from_assoc_array($aData);
  1375. }
  1376. }
  1377. ///////////////////////////////////////////////////////////////////////////
  1378. // Check programmaticaly built queries
  1379. ///////////////////////////////////////////////////////////////////////////
  1380. class TestQueriesByAPI extends TestBizModel
  1381. {
  1382. static public function GetName()
  1383. {
  1384. return 'Itop - queries build programmaticaly';
  1385. }
  1386. static public function GetDescription()
  1387. {
  1388. return 'Validate the DBObjectSearch API, through a set of complex (though realistic cases)';
  1389. }
  1390. protected function DoExecute()
  1391. {
  1392. // Note: relying on eval() - after upgrading to PHP 5.3 we can move to closure (aka anonymous functions)
  1393. $aQueries = array(
  1394. 'Basic (validate the test)' => array(
  1395. 'search' => '
  1396. $oSearch = DBObjectSearch::FromOQL("SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE org_id = 2");
  1397. ',
  1398. 'oql' => 'SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE P.org_id = 2'
  1399. ),
  1400. 'Double constraint' => array(
  1401. 'search' => '
  1402. $oSearch = DBObjectSearch::FromOQL("SELECT Contact AS c");
  1403. $sClass = $oSearch->GetClass();
  1404. $sFilterCode = "org_id";
  1405. $oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
  1406. if ($oAttDef->IsExternalKey())
  1407. {
  1408. $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
  1409. if ($sHierarchicalKeyCode !== false)
  1410. {
  1411. $oFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1412. $oFilter->AddCondition("id", 2);
  1413. $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1414. $oHKFilter->AddCondition_PointingTo(clone $oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
  1415. $oSearch->AddCondition_PointingTo(clone $oHKFilter, $sFilterCode);
  1416. $oFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1417. $oFilter->AddCondition("id", 2);
  1418. $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1419. $oHKFilter->AddCondition_PointingTo(clone $oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
  1420. $oSearch->AddCondition_PointingTo(clone $oHKFilter, $sFilterCode);
  1421. }
  1422. }
  1423. ',
  1424. 'oql' => 'SELECT Contact AS C JOIN Organization ???'
  1425. ),
  1426. 'Simplified issue' => array(
  1427. 'search' => '
  1428. $oSearch = DBObjectSearch::FromOQL("SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE O.id = 2");
  1429. $oOrgSearch = new DBObjectSearch("Organization", "O2");
  1430. $oOrgSearch->AddCondition("id", 2);
  1431. $oSearch->AddCondition_PointingTo($oOrgSearch, "org_id");
  1432. ',
  1433. 'oql' => 'SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id JOIN Organization AS O2 ON P.org_id = O2.id WHERE O.id = 2 AND O2.id = 2'
  1434. ),
  1435. );
  1436. foreach ($aQueries as $sQueryDesc => $aQuerySpec)
  1437. {
  1438. echo "<h2>Query $sQueryDesc</h2>\n";
  1439. echo "<p>Using code: ".highlight_string("<?php\n".trim($aQuerySpec['search'])."\n?".'>', true)."</p>\n";
  1440. echo "<p>Expected OQL: ".$aQuerySpec['oql']."</p>\n";
  1441. if (isset($oSearch))
  1442. {
  1443. unset($oSearch);
  1444. }
  1445. eval($aQuerySpec['search']);
  1446. $sResOQL = $oSearch->ToOQL();
  1447. echo "<p>Resulting OQL: ".$sResOQL."</p>\n";
  1448. echo "<pre>";
  1449. print_r($oSearch);
  1450. echo "</pre>";
  1451. $sSQL = $oSearch->MakeSelectQuery();
  1452. $res = CMDBSource::Query($sSQL);
  1453. foreach (CMDBSource::ExplainQuery($sSQL) as $aRow)
  1454. {
  1455. }
  1456. }
  1457. // throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  1458. }
  1459. }
  1460. ///////////////////////////////////////////////////////////////////////////
  1461. // Test bulk load API
  1462. ///////////////////////////////////////////////////////////////////////////
  1463. class TestItopBulkLoad extends TestBizModel
  1464. {
  1465. static public function GetName()
  1466. {
  1467. return 'Itop - test BulkChange class';
  1468. }
  1469. static public function GetDescription()
  1470. {
  1471. return 'Execute a bulk change at the Core API level';
  1472. }
  1473. protected function DoExecute()
  1474. {
  1475. $sLogin = 'testbulkload_'.time();
  1476. $oParser = new CSVParser("login,contactid->name,password,profile_list
  1477. _1_$sLogin,Picasso,secret1,profileid:10;reason:service manager|profileid->name:Problem Manager;'reason:toto;problem manager'
  1478. _2_$sLogin,Picasso,secret2,
  1479. ", ',', '"');
  1480. $aData = $oParser->ToArray(1, array('_login', '_contact_name', '_password', '_profiles'));
  1481. self::DumpVariable($aData);
  1482. $oUser = new UserLocal();
  1483. $oUser->Set('login', 'patator');
  1484. $oUser->Set('password', 'patator');
  1485. //$oUser->Set('contactid', 0);
  1486. //$oUser->Set('language', $sLanguage);
  1487. $aProfiles = array(
  1488. array(
  1489. 'profileid' => 10, // Service Manager
  1490. 'reason' => 'service manager',
  1491. ),
  1492. array(
  1493. 'profileid->name' => 'Problem Manager',
  1494. 'reason' => 'problem manager',
  1495. ),
  1496. );
  1497. $oBulk = new BulkChange(
  1498. 'UserLocal',
  1499. $aData,
  1500. // attributes
  1501. array('login' => '_login', 'password' => '_password', 'profile_list' => '_profiles'),
  1502. // ext keys
  1503. array('contactid' => array('name' => '_contact_name')),
  1504. // reconciliation
  1505. array('login'),
  1506. // Synchro - scope
  1507. "SELECT UserLocal",
  1508. // Synchro - set attribute on missing objects
  1509. array ('password' => 'terminated', 'login' => 'terminated'.time())
  1510. );
  1511. if (false)
  1512. {
  1513. $oMyChange = MetaModel::NewObject("CMDBChange");
  1514. $oMyChange->Set("date", time());
  1515. $oMyChange->Set("userinfo", "Testor");
  1516. $iChangeId = $oMyChange->DBInsert();
  1517. // echo "Created new change: $iChangeId</br>";
  1518. }
  1519. echo "<h3>Planned for loading...</h3>";
  1520. $aRes = $oBulk->Process();
  1521. self::DumpVariable($aRes);
  1522. if (false)
  1523. {
  1524. echo "<h3>Go for loading...</h3>";
  1525. $aRes = $oBulk->Process($oMyChange);
  1526. self::DumpVariable($aRes);
  1527. }
  1528. return;
  1529. }
  1530. }
  1531. ///////////////////////////////////////////////////////////////////////////
  1532. // Test data load
  1533. ///////////////////////////////////////////////////////////////////////////
  1534. class TestImportREST extends TestWebServices
  1535. {
  1536. static public function GetName()
  1537. {
  1538. return 'CSV import (REST)';
  1539. }
  1540. static public function GetDescription()
  1541. {
  1542. return 'Test various options and fonctionality of import.php';
  1543. }
  1544. protected function DoExecSingleLoad($aLoadSpec, $iTestId = null)
  1545. {
  1546. $sCsvData = $aLoadSpec['csvdata'];
  1547. echo "<div style=\"padding: 10;\">\n";
  1548. if (is_null($iTestId))
  1549. {
  1550. echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aLoadSpec['desc']}</h3>\n";
  1551. }
  1552. else
  1553. {
  1554. echo "<h3 style=\"background-color: #ddddff; padding: 10;\"><a href=\"?todo=exec&testid=TestImportREST&subtests=$iTestId\">$iTestId</a> - {$aLoadSpec['desc']}</h3>\n";
  1555. }
  1556. $aPostData = array('csvdata' => $sCsvData);
  1557. $aGetParams = array();
  1558. $aGetParamReport = array();
  1559. foreach($aLoadSpec['args'] as $sArg => $sValue)
  1560. {
  1561. $aGetParams[] = $sArg.'='.urlencode($sValue);
  1562. $aGetParamReport[] = $sArg.'='.$sValue;
  1563. }
  1564. $sGetParams = implode('&', $aGetParams);
  1565. $sLogin = isset($aLoadSpec['login']) ? $aLoadSpec['login'] : 'admin';
  1566. $sPassword = isset($aLoadSpec['password']) ? $aLoadSpec['password'] : 'admin';
  1567. $sRes = self::DoPostRequestAuth('../webservices/import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
  1568. $sArguments = implode('<br/>', $aGetParamReport);
  1569. if (strlen($sCsvData) > 5000)
  1570. {
  1571. $sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
  1572. }
  1573. else
  1574. {
  1575. $sCsvDataViewable = $sCsvData;
  1576. }
  1577. echo "<div style=\"\">\n";
  1578. echo " <div style=\"float:left; width:20%; padding:5; background-color:#eeeeff;\">\n";
  1579. echo " $sArguments\n";
  1580. echo " </div>\n";
  1581. echo " <div style=\"float:right; width:75%; padding:5; background-color:#eeeeff\">\n";
  1582. echo " <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
  1583. echo " </div>\n";
  1584. echo "</div>\n";
  1585. echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
  1586. echo "</div>\n";
  1587. }
  1588. protected function DoExecute()
  1589. {
  1590. $aLoads = array(
  1591. array(
  1592. 'desc' => 'Missing class',
  1593. 'login' => 'admin',
  1594. 'password' => 'admin',
  1595. 'args' => array(
  1596. ),
  1597. 'csvdata' => "xxx",
  1598. ),
  1599. array(
  1600. 'desc' => 'Wrong class',
  1601. 'login' => 'admin',
  1602. 'password' => 'admin',
  1603. 'args' => array(
  1604. 'class' => 'toto',
  1605. ),
  1606. 'csvdata' => "xxx",
  1607. ),
  1608. array(
  1609. 'desc' => 'Wrong output type',
  1610. 'login' => 'admin',
  1611. 'password' => 'admin',
  1612. 'args' => array(
  1613. 'class' => 'NetworkDevice',
  1614. 'output' => 'onthefly',
  1615. ),
  1616. 'csvdata' => "xxx",
  1617. ),
  1618. array(
  1619. 'desc' => 'Weird format, working anyhow...',
  1620. 'login' => 'admin',
  1621. 'password' => 'admin',
  1622. 'args' => array(
  1623. 'class' => 'Server',
  1624. 'output' => 'details',
  1625. 'separator' => '*',
  1626. 'qualifier' => '@',
  1627. 'reconciliationkeys' => 'org_id,name',
  1628. ),
  1629. 'csvdata' => 'name*org_id
  1630. server01*2
  1631. @server02@@combodo@* 2
  1632. server45*99',
  1633. ),
  1634. array(
  1635. 'desc' => 'Load an organization',
  1636. 'login' => 'admin',
  1637. 'password' => 'admin',
  1638. 'args' => array(
  1639. 'class' => 'Organization',
  1640. 'output' => 'details',
  1641. 'separator' => ';',
  1642. 'reconciliationkeys' => '',
  1643. ),
  1644. 'csvdata' => "name;code\nWorldCompany;WCY",
  1645. ),
  1646. array(
  1647. 'desc' => 'Load a location',
  1648. 'login' => 'admin',
  1649. 'password' => 'admin',
  1650. 'args' => array(
  1651. 'class' => 'Location',
  1652. 'output' => 'details',
  1653. 'separator' => ';',
  1654. 'reconciliationkeys' => '',
  1655. ),
  1656. 'csvdata' => "name;org_id;address\nParis;1;Centre de la Franca",
  1657. ),
  1658. array(
  1659. 'desc' => 'Load a person',
  1660. 'login' => 'admin',
  1661. 'password' => 'admin',
  1662. 'args' => array(
  1663. 'class' => 'Person',
  1664. 'output' => 'details',
  1665. 'separator' => ';',
  1666. 'reconciliationkeys' => '',
  1667. ),
  1668. 'csvdata' => "email;name;first_name;org_id;phone\njohn.foo@starac.com;Foo;John;1;+33(1)23456789",
  1669. ),
  1670. array(
  1671. 'desc' => 'Load a person - wrong email format',
  1672. 'login' => 'admin',
  1673. 'password' => 'admin',
  1674. 'args' => array(
  1675. 'class' => 'Person',
  1676. 'output' => 'details',
  1677. 'separator' => ';',
  1678. 'reconciliationkeys' => '',
  1679. ),
  1680. 'csvdata' => "email;name;first_name;org_id\nemailPASbon;Foo;John;1",
  1681. ),
  1682. array(
  1683. 'desc' => 'Load a team',
  1684. 'login' => 'admin',
  1685. 'password' => 'admin',
  1686. 'args' => array(
  1687. 'class' => 'Team',
  1688. 'output' => 'details',
  1689. 'separator' => ';',
  1690. 'reconciliationkeys' => '',
  1691. ),
  1692. 'csvdata' => "name;org_id;location_name\nSquadra Azzura2;1;Paris",
  1693. ),
  1694. array(
  1695. 'desc' => 'Load server',
  1696. 'login' => 'admin',
  1697. 'password' => 'admin',
  1698. 'args' => array(
  1699. 'class' => 'Server',
  1700. 'output' => 'details',
  1701. 'separator' => ';',
  1702. 'reconciliationkeys' => '',
  1703. ),
  1704. 'csvdata' => "name;status;owner_name;location_name;location_id->org_name;os_family;os_version;management_ip;cpu;ram;brand;model;serial_number\nlocalhost.;production;Demo;Grenoble;Demo;Ubuntu 9.10;2.6.31-19-generic-#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010;16.16.230.232;Intel(R) Core(TM)2 Duo CPU T7100 @ 1.80GHz;2005;Hewlett-Packard;HP Compaq 6510b (GM108UC#ABF);CNU7370BNP",
  1705. ),
  1706. array(
  1707. 'desc' => 'Load server (column header localized in english)',
  1708. 'login' => 'admin',
  1709. 'password' => 'admin',
  1710. 'args' => array(
  1711. 'class' => 'Server',
  1712. 'output' => 'details',
  1713. 'separator' => ';',
  1714. 'reconciliationkeys' => '',
  1715. ),
  1716. 'csvdata' => "Name;Status;Owner Organization;Location;location_id->org_name;OS Family;OS Version;Management IP;CPU;RAM;Brand;Model;Serial Number\nlocalhost.;production;Demo;Grenoble;Demo;Ubuntu 9.10;2.6.31-19-generic-#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010;16.16.230.232;Intel(R) Core(TM)2 Duo CPU T7100 @ 1.80GHz;2005;Hewlett-Packard;HP Compaq 6510b (GM108UC#ABF);CNU7370BNP",
  1717. ),
  1718. array(
  1719. 'desc' => 'Load server (directly from Export results)',
  1720. 'login' => 'admin',
  1721. 'password' => 'admin',
  1722. 'args' => array(
  1723. 'class' => 'Server',
  1724. 'output' => 'details',
  1725. 'reconciliationkeys' => '',
  1726. ),
  1727. 'csvdata' => 'id,Name,Status,Owner organization,Owner organization->Name,Business criticity,Brand,Model,Serial Number,Asset Reference,Description,Location,Location->Name,Location details,Management IP,Default Gateway,CPU,RAM,Hard Disk,OS Family,OS Version
  1728. 1,"dbserver1.demo.com","production",2,"Demo","medium","HP","DL380","","","ouille
  1729. [[Server:webserver.demo.com]]",1,"Grenoble","","10.1.1.10","255.255.255.0","2","16Gb","120Gb","Linux","Debian (Lenny)"',
  1730. ),
  1731. array(
  1732. 'desc' => 'Load server - wrong value for status',
  1733. 'login' => 'admin',
  1734. 'password' => 'admin',
  1735. 'args' => array(
  1736. 'class' => 'Server',
  1737. 'output' => 'details',
  1738. 'separator' => ';',
  1739. 'reconciliationkeys' => '',
  1740. ),
  1741. 'csvdata' => "name;status;owner_name;location_name;location_id->org_name;os_family;os_version;management_ip;cpu;ram;brand;model;serial_number\nlocalhost.;Production;Demo;Grenoble;Demo;Ubuntu 9.10;2.6.31-19-generic-#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010;16.16.230.232;Intel(R) Core(TM)2 Duo CPU T7100 @ 1.80GHz;2005;Hewlett-Packard;HP Compaq 6510b (GM108UC#ABF);CNU7370BNP",
  1742. ),
  1743. array(
  1744. 'desc' => 'Load NW if',
  1745. 'login' => 'admin',
  1746. 'password' => 'admin',
  1747. 'args' => array(
  1748. 'class' => 'NetworkInterface',
  1749. 'output' => 'details',
  1750. 'separator' => ';',
  1751. 'reconciliationkeys' => '',
  1752. ),
  1753. 'csvdata' => "name;status;org_id;device_name;physical_type;ip_address;ip_mask;mac_address;speed\neth0;implementation;2;localhost.;ethernet;16.16.230.232;255.255.240.0;00:1a:4b:68:e3:97;\nlo;implementation;2;localhost.;ethernet;127.0.0.1;255.0.0.0;;",
  1754. ),
  1755. // Data Bruno
  1756. array(
  1757. 'desc' => 'Load NW devices from real life',
  1758. 'login' => 'admin',
  1759. 'password' => 'admin',
  1760. 'args' => array(
  1761. 'class' => 'NetworkDevice',
  1762. 'output' => 'details',
  1763. 'separator' => ';',
  1764. 'reconciliationkeys' => 'org_id,Name',
  1765. ),
  1766. 'csvdata' => 'name;management_ip;importance;Owner organization->Name;type
  1767. truc-machin-bidule;172.15.255.150;high;My Company/Department;switch
  1768. 10.15.255.222;10.15.255.222;high;My Company/Department;switch',
  1769. ),
  1770. array(
  1771. 'desc' => 'Load NW ifs',
  1772. 'login' => 'admin',
  1773. 'password' => 'admin',
  1774. 'args' => array(
  1775. 'class' => 'NetworkInterface',
  1776. 'output' => 'details',
  1777. 'separator' => ';',
  1778. 'reconciliationkeys' => 'device_id->name,name',
  1779. ),
  1780. 'csvdata' => 'device_id->name;org_id->name;name;ip_address;ip_mask;speed;link_type;mac_address;physical_type
  1781. truc-machin-bidule;My Company/Department;"GigabitEthernet44";;;0;downlink;00 12 F2 CB C4 EB ;ethernet
  1782. truc-machin-bidule;My Company/Department;"GigabitEthernet38";;;0;downlink;00 12 F2 CB C4 E5 ;ethernet
  1783. un-autre;My Company/Department;"GigabitEthernet2/3";;;1000000000;uplink;00 12 F2 20 0F 1A ;ethernet',
  1784. ),
  1785. array(
  1786. 'desc' => 'The simplest data load',
  1787. 'login' => 'admin',
  1788. 'password' => 'admin',
  1789. 'args' => array(
  1790. 'class' => 'Location',
  1791. 'output' => 'details',
  1792. ),
  1793. 'csvdata' => "name\nParis",
  1794. ),
  1795. array(
  1796. 'desc' => 'The simplest data load + org',
  1797. 'login' => 'admin',
  1798. 'password' => 'admin',
  1799. 'args' => array(
  1800. 'class' => 'Location',
  1801. 'output' => 'details',
  1802. 'separator' => ';',
  1803. ),
  1804. 'csvdata' => "name;org_id\nParis;2",
  1805. ),
  1806. array(
  1807. 'desc' => 'The simplest data load + org (name)',
  1808. 'login' => 'admin',
  1809. 'password' => 'admin',
  1810. 'args' => array(
  1811. 'class' => 'Location',
  1812. 'output' => 'details',
  1813. 'separator' => ';',
  1814. ),
  1815. 'csvdata' => "name;org_name\nParis;Demo",
  1816. ),
  1817. array(
  1818. 'desc' => 'The simplest data load + org (code)',
  1819. 'login' => 'admin',
  1820. 'password' => 'admin',
  1821. 'args' => array(
  1822. 'class' => 'Location',
  1823. 'output' => 'details',
  1824. 'separator' => ';',
  1825. ),
  1826. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1827. ),
  1828. array(
  1829. 'desc' => 'Ouput: summary',
  1830. 'login' => 'admin',
  1831. 'password' => 'admin',
  1832. 'args' => array(
  1833. 'class' => 'Location',
  1834. 'output' => 'summary',
  1835. 'separator' => ';',
  1836. ),
  1837. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1838. ),
  1839. array(
  1840. 'desc' => 'Ouput: retcode',
  1841. 'login' => 'admin',
  1842. 'password' => 'admin',
  1843. 'args' => array(
  1844. 'class' => 'Location',
  1845. 'output' => 'retcode',
  1846. 'separator' => ';',
  1847. ),
  1848. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1849. ),
  1850. array(
  1851. 'desc' => 'Error in reconciliation list',
  1852. 'login' => 'admin',
  1853. 'password' => 'admin',
  1854. 'args' => array(
  1855. 'class' => 'Location',
  1856. 'output' => 'details',
  1857. 'separator' => ';',
  1858. 'reconciliationkeys' => 'org_id',
  1859. ),
  1860. 'csvdata' => "org_name;name\nDemo;Paris",
  1861. ),
  1862. array(
  1863. 'desc' => 'Error in attribute list that does not allow to compute reconciliation scheme',
  1864. 'login' => 'admin',
  1865. 'password' => 'admin',
  1866. 'args' => array(
  1867. 'class' => 'Location',
  1868. 'output' => 'details',
  1869. 'separator' => ';',
  1870. ),
  1871. 'csvdata' => "org_name;country\nDemo;France",
  1872. ),
  1873. array(
  1874. 'desc' => 'Error in attribute list - case A',
  1875. 'login' => 'admin',
  1876. 'password' => 'admin',
  1877. 'args' => array(
  1878. 'class' => 'Location',
  1879. 'output' => 'details',
  1880. 'separator' => ';',
  1881. ),
  1882. 'csvdata' => "name;org\nParis;2",
  1883. ),
  1884. array(
  1885. 'desc' => 'Error in attribute list - case B1 (key->attcode)',
  1886. 'login' => 'admin',
  1887. 'password' => 'admin',
  1888. 'args' => array(
  1889. 'class' => 'Location',
  1890. 'output' => 'details',
  1891. 'separator' => ';',
  1892. ),
  1893. 'csvdata' => "name;org->code\nParis;DEMO",
  1894. ),
  1895. array(
  1896. 'desc' => 'Error in attribute list - case B2 (key->attcode)',
  1897. 'login' => 'admin',
  1898. 'password' => 'admin',
  1899. 'args' => array(
  1900. 'class' => 'Location',
  1901. 'output' => 'details',
  1902. 'separator' => ';',
  1903. ),
  1904. 'csvdata' => "name;org_id->duns\nParis;DEMO",
  1905. ),
  1906. array(
  1907. 'desc' => 'Always changing... special comment in change tracking',
  1908. 'login' => 'admin',
  1909. 'password' => 'admin',
  1910. 'args' => array(
  1911. 'class' => 'Location',
  1912. 'output' => 'details',
  1913. 'separator' => ';',
  1914. 'comment' => 'automated testing'
  1915. ),
  1916. 'csvdata' => "org_name;name;address\nDemo;Le pantheon;Addresse bidon:".((string)microtime(true)),
  1917. ),
  1918. array(
  1919. 'desc' => 'Always changing... but "simulate"',
  1920. 'login' => 'admin',
  1921. 'password' => 'admin',
  1922. 'args' => array(
  1923. 'class' => 'Location',
  1924. 'output' => 'details',
  1925. 'separator' => ';',
  1926. 'simulate' => '1',
  1927. 'comment' => 'SHOULD NEVER APPEAR IN THE HISTORY'
  1928. ),
  1929. 'csvdata' => "org_name;name;address\nDemo;Le pantheon;restore address?",
  1930. ),
  1931. array(
  1932. 'desc' => 'Load a user account',
  1933. 'login' => 'admin',
  1934. 'password' => 'admin',
  1935. 'args' => array(
  1936. 'class' => 'UserLocal',
  1937. 'output' => 'details',
  1938. 'separator' => ',',
  1939. 'simulate' => '0',
  1940. 'comment' => 'automated testing'
  1941. ),
  1942. 'csvdata' => "login,password,profile_list\nby_import_csv,fakepwd,profileid->name:Configuration Manager|profileid:10;reason:direct id",
  1943. ),
  1944. );
  1945. $sSubTests = utils::ReadParam('subtests', null, true, 'raw_data');
  1946. if (is_null($sSubTests))
  1947. {
  1948. foreach ($aLoads as $iTestId => $aLoadSpec)
  1949. {
  1950. $this->DoExecSingleLoad($aLoadSpec, $iTestId);
  1951. }
  1952. }
  1953. else
  1954. {
  1955. $aSubTests = explode(',', $sSubTests);
  1956. foreach ($aSubTests as $iTestId)
  1957. {
  1958. $this->DoExecSingleLoad($aLoads[$iTestId], $iTestId);
  1959. }
  1960. }
  1961. }
  1962. }
  1963. ///////////////////////////////////////////////////////////////////////////
  1964. // Test massive data load
  1965. ///////////////////////////////////////////////////////////////////////////
  1966. define('IMPORT_COUNT', 4000);
  1967. class TestImportRESTMassive extends TestImportREST
  1968. {
  1969. static public function GetName()
  1970. {
  1971. return 'CSV import (REST) - HUGE data set ('.IMPORT_COUNT.' PCs)';
  1972. }
  1973. static public function GetDescription()
  1974. {
  1975. return 'Stress import.php';
  1976. }
  1977. protected function DoExecute()
  1978. {
  1979. $aLoadSpec = array(
  1980. 'desc' => 'Loading PCs: '.IMPORT_COUNT,
  1981. 'args' => array(
  1982. 'class' => 'PC',
  1983. 'output' => 'summary',
  1984. ),
  1985. 'csvdata' => "name;org_id;brand\n",
  1986. );
  1987. for($i = 0 ; $i <= IMPORT_COUNT ; $i++)
  1988. {
  1989. $aLoadSpec['csvdata'] .= "pc.import.$i;2;Combodo\n";
  1990. }
  1991. $this->DoExecSingleLoad($aLoadSpec);
  1992. }
  1993. }
  1994. ///////////////////////////////////////////////////////////////////////////
  1995. // Test data exchange
  1996. ///////////////////////////////////////////////////////////////////////////
  1997. class TestDataExchange extends TestBizModel
  1998. {
  1999. static public function GetName()
  2000. {
  2001. return 'Data exchange';
  2002. }
  2003. static public function GetDescription()
  2004. {
  2005. return 'Test REST services: synchro_import and synchro_exec';
  2006. }
  2007. protected function DoExecScenario($aSingleScenario)
  2008. {
  2009. echo "<div style=\"padding: 10;\">\n";
  2010. echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aSingleScenario['desc']}</h3>\n";
  2011. $sClass = $aSingleScenario['target_class'];
  2012. $aTargetData = $aSingleScenario['target_data'];
  2013. $aSourceData = $aSingleScenario['source_data'];
  2014. $aTargetAttributes = array_shift($aTargetData);
  2015. $aSourceAttributes = array_shift($aSourceData);
  2016. if (count($aSourceData) + 1 != count($aTargetData))
  2017. {
  2018. throw new Exception("Target data must contain exactly ".(count($aSourceData) + 1)." items, found ".count($aTargetData));
  2019. }
  2020. // Create the data source
  2021. //
  2022. $oDataSource = new SynchroDataSource();
  2023. $oDataSource->Set('name', 'Test data sync '.time());
  2024. $oDataSource->Set('description', 'unit test - created automatically');
  2025. $oDataSource->Set('status', 'production');
  2026. $oDataSource->Set('user_id', 0);
  2027. $oDataSource->Set('scope_class', $sClass);
  2028. $oDataSource->Set('scope_restriction', '');
  2029. $oDataSource->Set('full_load_periodicity', $aSingleScenario['full_load_periodicity']);
  2030. $oDataSource->Set('reconciliation_policy', $aSingleScenario['reconciliation_policy']);
  2031. $oDataSource->Set('action_on_zero', $aSingleScenario['action_on_zero']);
  2032. $oDataSource->Set('action_on_one', $aSingleScenario['action_on_one']);
  2033. $oDataSource->Set('action_on_multiple', $aSingleScenario['action_on_multiple']);
  2034. $oDataSource->Set('delete_policy', $aSingleScenario['delete_policy']);
  2035. $oDataSource->Set('delete_policy_update', $aSingleScenario['delete_policy_update']);
  2036. $oDataSource->Set('delete_policy_retention', $aSingleScenario['delete_policy_retention']);
  2037. $iDataSourceId = $this->ObjectToDB($oDataSource, true /* reload */);
  2038. $oAttributeSet = $oDataSource->Get('attribute_list');
  2039. while ($oAttribute = $oAttributeSet->Fetch())
  2040. {
  2041. if (array_key_exists($oAttribute->Get('attcode'), $aSingleScenario['attributes']))
  2042. {
  2043. $aAttribInfo = $aSingleScenario['attributes'][$oAttribute->Get('attcode')];
  2044. if (array_key_exists('reconciliation_attcode', $aAttribInfo))
  2045. {
  2046. $oAttribute->Set('reconciliation_attcode', $aAttribInfo['reconciliation_attcode']);
  2047. }
  2048. $oAttribute->Set('update', $aAttribInfo['do_update']);
  2049. $oAttribute->Set('reconcile', $aAttribInfo['do_reconcile']);
  2050. }
  2051. else
  2052. {
  2053. $oAttribute->Set('update', false);
  2054. $oAttribute->Set('reconcile', false);
  2055. }
  2056. $this->UpdateObjectInDB($oAttribute);
  2057. }
  2058. // Prepare list of prefixes -> make sure objects are unique with regard to the reconciliation scheme
  2059. $aPrefixes = array(); // attcode => prefix
  2060. foreach($aSourceAttributes as $iDummy => $sAttCode)
  2061. {
  2062. $aPrefixes[$sAttCode] = ''; // init with something
  2063. }
  2064. foreach($aSingleScenario['attributes'] as $sAttCode => $aAttribInfo)
  2065. {
  2066. if (isset($aAttribInfo['automatic_prefix']) && $aAttribInfo['automatic_prefix'])
  2067. {
  2068. $aPrefixes[$sAttCode] = 'TEST_'.$iDataSourceId.'_';
  2069. }
  2070. }
  2071. // List existing objects (to be ignored in the analysis
  2072. //
  2073. $oAllObjects = new DBObjectSet(new DBObjectSearch($sClass));
  2074. $aExisting = $oAllObjects->ToArray(true);
  2075. $sExistingIds = implode(', ', array_keys($aExisting));
  2076. // Create the initial object list
  2077. //
  2078. $aInitialTarget = $aTargetData[0];
  2079. foreach($aInitialTarget as $aObjFields)
  2080. {
  2081. $oNewTarget = MetaModel::NewObject($sClass);
  2082. foreach($aTargetAttributes as $iAtt => $sAttCode)
  2083. {
  2084. $oNewTarget->Set($sAttCode, $aPrefixes[$sAttCode].$aObjFields[$iAtt]);
  2085. }
  2086. $this->ObjectToDB($oNewTarget);
  2087. }
  2088. foreach($aTargetData as $iRow => $aExpectedObjects)
  2089. {
  2090. sleep(2);
  2091. // Check the status (while ignoring existing objects)
  2092. //
  2093. if (empty($sExistingIds))
  2094. {
  2095. $oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass"));
  2096. }
  2097. else
  2098. {
  2099. $oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass WHERE id NOT IN($sExistingIds)"));
  2100. }
  2101. $aFound = $oObjects->ToArray();
  2102. $aErrors_Unexpected = array();
  2103. foreach($aFound as $iObj => $oObj)
  2104. {
  2105. // Is this object in the expected objects list
  2106. $bFoundMatch = false;
  2107. foreach($aExpectedObjects as $iExp => $aValues)
  2108. {
  2109. $bDoesMatch = true;
  2110. foreach($aTargetAttributes as $iCol => $sAttCode)
  2111. {
  2112. if ($oObj->Get($sAttCode) != $aPrefixes[$sAttCode].$aValues[$iCol])
  2113. {
  2114. $bDoesMatch = false;
  2115. break;
  2116. }
  2117. }
  2118. if ($bDoesMatch)
  2119. {
  2120. $bFoundMatch = true;
  2121. unset($aExpectedObjects[$iExp]);
  2122. break;
  2123. }
  2124. }
  2125. if (!$bFoundMatch)
  2126. {
  2127. $aErrors_Unexpected[] = $oObj->GetKey();
  2128. }
  2129. }
  2130. // Display the current status
  2131. //
  2132. echo "<p>Status at step $iRow</p>\n";
  2133. $aCurrentDataSet = array();
  2134. foreach($aFound as $iObj => $oObj)
  2135. {
  2136. $aObjDesc = array(
  2137. 'Status' => (in_array($iObj, $aErrors_Unexpected) ? 'unexpected' : 'ok'),
  2138. 'Object' => $oObj->GetHyperLink()
  2139. );
  2140. foreach($aTargetAttributes as $iCol => $sAttCode)
  2141. {
  2142. $aObjDesc[$sAttCode] = $oObj->Get($sAttCode);
  2143. }
  2144. $aCurrentDataSet[] = $aObjDesc;
  2145. }
  2146. if (count($aExpectedObjects) > 0)
  2147. {
  2148. foreach($aExpectedObjects as $iExp => $aValues)
  2149. {
  2150. $aObjDesc = array(
  2151. 'Status' => 'missing',
  2152. 'Object' => 'n/a'
  2153. );
  2154. foreach($aTargetAttributes as $iCol => $sAttCode)
  2155. {
  2156. $aObjDesc[$sAttCode] = $aPrefixes[$sAttCode].$aValues[$iCol];
  2157. }
  2158. $aCurrentDataSet[] = $aObjDesc;
  2159. }
  2160. }
  2161. echo MyHelpers::make_table_from_assoc_array($aCurrentDataSet);
  2162. if ((count($aErrors_Unexpected) > 0) || (count($aExpectedObjects) > 0))
  2163. {
  2164. throw new UnitTestException("The current status in iTop does not match the expectations");
  2165. }
  2166. // If not on the final row, run a data exchange sequence
  2167. //
  2168. if (array_key_exists($iRow, $aSourceData))
  2169. {
  2170. $aToBeLoaded = $aSourceData[$iRow];
  2171. $sCsvData = implode(';', $aSourceAttributes)."\n";
  2172. foreach($aToBeLoaded as $aDataRow)
  2173. {
  2174. $aFinalData = array();
  2175. foreach($aDataRow as $iCol => $value)
  2176. {
  2177. if (is_null($value))
  2178. {
  2179. $aFinalData[] = '<NULL>';
  2180. }
  2181. else
  2182. {
  2183. $sAttCode = $aSourceAttributes[$iCol];
  2184. $aFinalData[] = $aPrefixes[$sAttCode].$value;
  2185. }
  2186. }
  2187. $sCsvData .= implode(';', $aFinalData)."\n";
  2188. }
  2189. $aPostData = array('csvdata' => $sCsvData);
  2190. $aImportArgs = array(
  2191. 'data_source_id' => $iDataSourceId,
  2192. 'separator' => ';',
  2193. 'simulate' => 0,
  2194. 'output' => 'details',
  2195. );
  2196. $aGetParams = array();
  2197. $aGetParamReport = array();
  2198. foreach($aImportArgs as $sArg => $sValue)
  2199. {
  2200. $aGetParams[] = $sArg.'='.urlencode($sValue);
  2201. $aGetParamReport[] = $sArg.'='.$sValue;
  2202. }
  2203. $sGetParams = implode('&', $aGetParams);
  2204. $sLogin = isset($aSingleScenario['login']) ? $aSingleScenario['login'] : 'admin';
  2205. $sPassword = isset($aSingleScenario['password']) ? $aSingleScenario['password'] : 'admin';
  2206. $sRes = self::DoPostRequestAuth('../synchro/synchro_import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
  2207. // Report the load results
  2208. //
  2209. if (strlen($sCsvData) > 5000)
  2210. {
  2211. $sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
  2212. }
  2213. else
  2214. {
  2215. $sCsvDataViewable = $sCsvData;
  2216. }
  2217. $sCsvDataViewable = htmlentities($sCsvDataViewable, ENT_QUOTES, 'UTF-8');
  2218. echo "<div style=\"\">\n";
  2219. echo " <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
  2220. echo "</div>\n";
  2221. echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
  2222. if (stripos($sRes, 'exception') !== false)
  2223. {
  2224. throw new UnitTestException('Encountered an Exception during the last import/synchro');
  2225. }
  2226. }
  2227. }
  2228. return;
  2229. echo "</div>\n";
  2230. }
  2231. protected function DoExecute()
  2232. {
  2233. /*
  2234. $aScenarios = array(
  2235. array(
  2236. 'desc' => 'Load user logins',
  2237. 'login' => 'admin',
  2238. 'password' => 'admin',
  2239. 'target_class' => 'UserLocal',
  2240. 'full_load_periodicity' => 3600, // should be ignored in this case
  2241. 'reconciliation_policy' => 'use_attributes',
  2242. 'action_on_zero' => 'create',
  2243. 'action_on_one' => 'update',
  2244. 'action_on_multiple' => 'error',
  2245. 'delete_policy' => 'delete',
  2246. 'delete_policy_update' => '',
  2247. 'delete_policy_retention' => 0,
  2248. 'source_data' => array(
  2249. array('primary_key', 'login', 'password', 'profile_list'),
  2250. array(
  2251. array('user_A', 'login_A', 'password_A', 'profileid:10;reason:he/she is managing services'),
  2252. ),
  2253. ),
  2254. 'target_data' => array(
  2255. array('login'),
  2256. array(
  2257. // Initial state
  2258. ),
  2259. array(
  2260. array('login_A'),
  2261. ),
  2262. ),
  2263. 'attributes' => array(
  2264. 'login' => array(
  2265. 'do_reconcile' => true,
  2266. 'do_update' => true,
  2267. 'automatic_prefix' => true, // unique id (for unit testing)
  2268. ),
  2269. 'password' => array(
  2270. 'do_reconcile' => false,
  2271. 'do_update' => true,
  2272. ),
  2273. 'profile_list' => array(
  2274. 'do_reconcile' => false,
  2275. 'do_update' => true,
  2276. ),
  2277. ),
  2278. ),
  2279. );
  2280. */
  2281. $aScenarios = array(
  2282. array(
  2283. 'desc' => 'Simple scenario with delete option (and extkey given as org/name)',
  2284. 'login' => 'admin',
  2285. 'password' => 'admin',
  2286. 'target_class' => 'ApplicationSolution',
  2287. 'full_load_periodicity' => 3600, // should be ignored in this case
  2288. 'reconciliation_policy' => 'use_attributes',
  2289. 'action_on_zero' => 'create',
  2290. 'action_on_one' => 'update',
  2291. 'action_on_multiple' => 'error',
  2292. 'delete_policy' => 'delete',
  2293. 'delete_policy_update' => '',
  2294. 'delete_policy_retention' => 0,
  2295. 'source_data' => array(
  2296. array('primary_key', 'org_id', 'name', 'status'),
  2297. array(
  2298. array('obj_A', null, 'obj_A', 'production'), // org_id unchanged
  2299. array('obj_B', '_DUMMY_', 'obj_B', 'production'), // error, '_DUMMY_' unknown
  2300. array('obj_C', 'SOMECODE', 'obj_C', 'production'),
  2301. array('obj_D', null, 'obj_D', 'production'),
  2302. array('obj_E', '_DUMMY_', 'obj_E', 'production'),
  2303. ),
  2304. array(
  2305. ),
  2306. array(
  2307. ),
  2308. ),
  2309. 'target_data' => array(
  2310. array('org_id', 'name', 'status'),
  2311. array(
  2312. // Initial state
  2313. array(2, 'obj_A', 'production'),
  2314. array(2, 'obj_B', 'production'),
  2315. ),
  2316. array(
  2317. array(2, 'obj_A', 'production'),
  2318. array(2, 'obj_B', 'production'),
  2319. array(1, 'obj_C', 'production'),
  2320. ),
  2321. array(
  2322. array(2, 'obj_A', 'production'),
  2323. array(2, 'obj_B', 'production'),
  2324. // deleted !
  2325. ),
  2326. // The only diff here is into the log
  2327. array(
  2328. array(2, 'obj_A', 'production'),
  2329. array(2, 'obj_B', 'production'),
  2330. // deleted !
  2331. ),
  2332. ),
  2333. 'attributes' => array(
  2334. 'org_id' => array(
  2335. 'do_reconcile' => false,
  2336. 'do_update' => true,
  2337. 'reconciliation_attcode' => 'code',
  2338. ),
  2339. 'name' => array(
  2340. 'do_reconcile' => true,
  2341. 'do_update' => true,
  2342. 'automatic_prefix' => true, // unique id
  2343. ),
  2344. 'status' => array(
  2345. 'do_reconcile' => false,
  2346. 'do_update' => true,
  2347. ),
  2348. ),
  2349. ),
  2350. // );
  2351. // $aXXXXScenarios = array(
  2352. array(
  2353. 'desc' => 'Update then delete with retention (to complete with manual testing) and reconciliation on org/name',
  2354. 'login' => 'admin',
  2355. 'password' => 'admin',
  2356. 'target_class' => 'ApplicationSolution',
  2357. 'full_load_periodicity' => 3600,
  2358. 'reconciliation_policy' => 'use_attributes',
  2359. 'action_on_zero' => 'create',
  2360. 'action_on_one' => 'update',
  2361. 'action_on_multiple' => 'error',
  2362. 'delete_policy' => 'update_then_delete',
  2363. 'delete_policy_update' => 'status:obsolete',
  2364. 'delete_policy_retention' => 15,
  2365. 'source_data' => array(
  2366. array('primary_key', 'org_id', 'name', 'status'),
  2367. array(
  2368. array('obj_A', 'Demo', 'obj_A', 'production'),
  2369. ),
  2370. array(
  2371. ),
  2372. ),
  2373. 'target_data' => array(
  2374. array('org_id', 'name', 'status'),
  2375. array(
  2376. // Initial state
  2377. ),
  2378. array(
  2379. array(2, 'obj_A', 'production'),
  2380. ),
  2381. array(
  2382. array(2, 'obj_A', 'obsolete'),
  2383. // deleted !
  2384. ),
  2385. ),
  2386. 'attributes' => array(
  2387. 'org_id' => array(
  2388. 'do_reconcile' => true,
  2389. 'do_update' => true,
  2390. 'reconciliation_attcode' => 'name',
  2391. ),
  2392. 'name' => array(
  2393. 'do_reconcile' => true,
  2394. 'do_update' => true,
  2395. 'automatic_prefix' => true, // unique id
  2396. ),
  2397. 'status' => array(
  2398. 'do_reconcile' => false,
  2399. 'do_update' => true,
  2400. ),
  2401. ),
  2402. ),
  2403. //);
  2404. //$aXXScenarios = array(
  2405. array(
  2406. 'desc' => 'Simple scenario loading a few ApplicationSolution',
  2407. 'login' => 'admin',
  2408. 'password' => 'admin',
  2409. 'target_class' => 'ApplicationSolution',
  2410. 'full_load_periodicity' => 3600,
  2411. 'reconciliation_policy' => 'use_attributes',
  2412. 'action_on_zero' => 'create',
  2413. 'action_on_one' => 'update',
  2414. 'action_on_multiple' => 'error',
  2415. 'delete_policy' => 'update',
  2416. 'delete_policy_update' => 'status:obsolete',
  2417. 'delete_policy_retention' => 0,
  2418. 'source_data' => array(
  2419. array('primary_key', 'org_id', 'name', 'status'),
  2420. array(
  2421. array('obj_A', 2, 'obj_A', 'production'),
  2422. array('obj_B', 2, 'obj_B', 'implementation'),
  2423. array('obj_C', 2, 'obj_C', 'implementation'),
  2424. ),
  2425. array(
  2426. array('obj_A', 2, 'obj_A', 'production'),
  2427. array('obj_B', 2, 'obj_B', 'implementation'),
  2428. array('obj_C', 2, 'obj_C', 'implementation'),
  2429. ),
  2430. array(
  2431. array('obj_A', 2, 'obj_A', 'production'),
  2432. array('obj_C', 2, 'obj_C', 'implementation'),
  2433. array('obj_D', 2, 'obj_D', 'implementation'),
  2434. ),
  2435. array(
  2436. array('obj_C', 2, 'obj_C', 'production'),
  2437. ),
  2438. array(
  2439. array('obj_C', 2, 'obj_C', 'production'),
  2440. ),
  2441. ),
  2442. 'target_data' => array(
  2443. array('org_id', 'name', 'status'),
  2444. array(
  2445. // Initial state
  2446. array(2, 'obj_A', 'implementation'),
  2447. array(2, 'obj_B', 'production'),
  2448. array(2, 'obj_B', 'implementation'),
  2449. ),
  2450. array(
  2451. array(2, 'obj_A', 'production'),
  2452. array(2, 'obj_B', 'production'),
  2453. array(2, 'obj_B', 'implementation'),
  2454. array(2, 'obj_C', 'implementation'),
  2455. ),
  2456. array(
  2457. array(2, 'obj_A', 'production'),
  2458. array(2, 'obj_B', 'production'),
  2459. array(2, 'obj_B', 'implementation'),
  2460. array(2, 'obj_C', 'implementation'),
  2461. ),
  2462. array(
  2463. array(2, 'obj_A', 'production'),
  2464. array(2, 'obj_B', 'production'),
  2465. array(2, 'obj_B', 'implementation'),
  2466. array(2, 'obj_C', 'implementation'),
  2467. array(2, 'obj_D', 'implementation'),
  2468. ),
  2469. array(
  2470. array(2, 'obj_A', 'obsolete'),
  2471. array(2, 'obj_B', 'production'),
  2472. array(2, 'obj_B', 'implementation'),
  2473. array(2, 'obj_C', 'production'),
  2474. array(2, 'obj_D', 'obsolete'),
  2475. ),
  2476. array(
  2477. array(2, 'obj_A', 'obsolete'),
  2478. array(2, 'obj_B', 'production'),
  2479. array(2, 'obj_B', 'implementation'),
  2480. array(2, 'obj_C', 'production'),
  2481. array(2, 'obj_D', 'obsolete'),
  2482. ),
  2483. ),
  2484. 'attributes' => array(
  2485. 'org_id' => array(
  2486. 'do_reconcile' => false,
  2487. 'do_update' => true,
  2488. ),
  2489. 'name' => array(
  2490. 'do_reconcile' => true,
  2491. 'do_update' => true,
  2492. 'automatic_prefix' => true, // unique id
  2493. ),
  2494. 'status' => array(
  2495. 'do_reconcile' => false,
  2496. 'do_update' => true,
  2497. ),
  2498. ),
  2499. ),
  2500. );
  2501. foreach ($aScenarios as $aSingleScenario)
  2502. {
  2503. $this->DoExecScenario($aSingleScenario);
  2504. }
  2505. }
  2506. }
  2507. ///////////////////////////////////////////////////////////////////////////
  2508. // Test SOAP services
  2509. ///////////////////////////////////////////////////////////////////////////
  2510. $aCreateTicketSpecs = array(
  2511. array(
  2512. 'service_category' => 'BasicServices',
  2513. 'verb' => 'GetVersion',
  2514. // 'expected result' => '1.0.1',
  2515. 'expected result' => '$ITOP_VERSION$ [dev]',
  2516. 'explain result' => 'no comment!',
  2517. 'args' => array(),
  2518. ),
  2519. array(
  2520. 'service_category' => '',
  2521. 'verb' => 'CreateIncidentTicket',
  2522. 'expected result' => true,
  2523. 'explain result' => 'link attribute unknown + a CI not found',
  2524. 'args' => array(
  2525. 'admin', /* sLogin */
  2526. 'admin', /* sPassword */
  2527. 'desc of ticket', /* sDescription */
  2528. 'initial situation blah blah blah', /* sInitialSituation */
  2529. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2530. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2531. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Telecom and connectivity'))), /* aServiceDesc */
  2532. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Network Troubleshooting'))), /* aServiceSubcategoryDesc */
  2533. 'sub product of the service', /* sProduct */
  2534. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2535. array(
  2536. new SOAPLinkCreationSpec(
  2537. 'InfrastructureCI',
  2538. array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
  2539. array(new SOAPAttributeValue('impacting', 'very critical'))
  2540. ),
  2541. new SOAPLinkCreationSpec(
  2542. 'NetworkDevice',
  2543. array(new SOAPSearchCondition('name', 'switch01')),
  2544. array(new SOAPAttributeValue('impact', 'who cares'))
  2545. ),
  2546. new SOAPLinkCreationSpec(
  2547. 'Server',
  2548. array(new SOAPSearchCondition('name', 'thisone')),
  2549. array(new SOAPAttributeValue('impact', 'our lives'))
  2550. ),
  2551. ), /* aImpact */
  2552. '1', /* sImpact */
  2553. '1', /* sUrgency */
  2554. ),
  2555. ),
  2556. array(
  2557. 'service_category' => '',
  2558. 'verb' => 'CreateIncidentTicket',
  2559. 'expected result' => true,
  2560. 'explain result' => 'caller not specified',
  2561. 'args' => array(
  2562. 'admin', /* sLogin */
  2563. 'admin', /* sPassword */
  2564. 'PC burning', /* sDescription */
  2565. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2566. new SOAPExternalKeySearch(), /* aCallerDesc */
  2567. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2568. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2569. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2570. 'sub product of the service', /* sProduct */
  2571. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2572. array(
  2573. new SOAPLinkCreationSpec(
  2574. 'InfrastructureCI',
  2575. array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
  2576. array()
  2577. ), /* aImpact */
  2578. ),
  2579. '1', /* sImpact */
  2580. '1', /* sUrgency */
  2581. ),
  2582. ),
  2583. array(
  2584. 'service_category' => '',
  2585. 'verb' => 'CreateIncidentTicket',
  2586. 'expected result' => false,
  2587. 'explain result' => 'wrong class on CI to attach',
  2588. 'args' => array(
  2589. 'admin', /* sLogin */
  2590. 'admin', /* sPassword */
  2591. 'PC burning', /* sDescription */
  2592. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2593. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2594. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2595. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2596. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2597. 'sub product of the service', /* sProduct */
  2598. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2599. array(
  2600. new SOAPLinkCreationSpec(
  2601. 'logInfra',
  2602. array(new SOAPSearchCondition('dummyfiltercode', 2)),
  2603. array(new SOAPAttributeValue('impact', 'very critical'))
  2604. ),
  2605. ), /* aImpact */
  2606. '1', /* sImpact */
  2607. '1', /* sUrgency */
  2608. ),
  2609. ),
  2610. array(
  2611. 'service_category' => '',
  2612. 'verb' => 'CreateIncidentTicket',
  2613. 'expected result' => false,
  2614. 'explain result' => 'wrong search condition on CI to attach',
  2615. 'args' => array(
  2616. 'admin', /* sLogin */
  2617. 'admin', /* sPassword */
  2618. 'PC burning', /* sDescription */
  2619. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2620. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2621. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2622. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2623. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2624. 'sub product of the service', /* sProduct */
  2625. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2626. array(
  2627. new SOAPLinkCreationSpec(
  2628. 'InfrastructureCI',
  2629. array(new SOAPSearchCondition('dummyfiltercode', 2)),
  2630. array(new SOAPAttributeValue('impact', 'very critical'))
  2631. ),
  2632. ), /* aImpact */
  2633. '1', /* sImpact */
  2634. '1', /* sUrgency */
  2635. ),
  2636. ),
  2637. array(
  2638. 'service_category' => '',
  2639. 'verb' => 'CreateIncidentTicket',
  2640. 'expected result' => true,
  2641. 'explain result' => 'no CI to attach (empty array)',
  2642. 'args' => array(
  2643. 'admin', /* sLogin */
  2644. 'admin', /* sPassword */
  2645. 'Houston not reachable', /* sDescription */
  2646. 'Tried to join the shuttle', /* sInitialSituation */
  2647. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2648. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2649. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2650. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2651. 'sub product of the service', /* sProduct */
  2652. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2653. array(
  2654. ), /* aImpact */
  2655. '1', /* sImpact */
  2656. '1', /* sUrgency */
  2657. ),
  2658. ),
  2659. array(
  2660. 'service_category' => '',
  2661. 'verb' => 'CreateIncidentTicket',
  2662. 'expected result' => true,
  2663. 'explain result' => 'no CI to attach (null)',
  2664. 'args' => array(
  2665. 'admin', /* sLogin */
  2666. 'admin', /* sPassword */
  2667. 'Houston not reachable', /* sDescription */
  2668. 'Tried to join the shuttle', /* sInitialSituation */
  2669. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2670. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2671. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2672. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2673. 'sub product of the service', /* sProduct */
  2674. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2675. null, /* aImpact */
  2676. '1', /* sImpact */
  2677. '1', /* sUrgency */
  2678. ),
  2679. ),
  2680. array(
  2681. 'service_category' => '',
  2682. 'verb' => 'CreateIncidentTicket',
  2683. 'expected result' => true,
  2684. 'explain result' => 'caller unknown',
  2685. 'args' => array(
  2686. 'admin', /* sLogin */
  2687. 'admin', /* sPassword */
  2688. 'Houston not reachable', /* sDescription */
  2689. 'Tried to join the shuttle', /* sInitialSituation */
  2690. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1000))), /* aCallerDesc */
  2691. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2692. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2693. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2694. 'sub product of the service', /* sProduct */
  2695. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2696. array(
  2697. ), /* aImpact */
  2698. '1', /* sImpact */
  2699. '1', /* sUrgency */
  2700. ),
  2701. ),
  2702. array(
  2703. 'service_category' => '',
  2704. 'verb' => 'CreateIncidentTicket',
  2705. 'expected result' => false,
  2706. 'explain result' => 'wrong values for impact and urgency',
  2707. 'args' => array(
  2708. 'admin', /* sLogin */
  2709. 'admin', /* sPassword */
  2710. 'Houston not reachable', /* sDescription */
  2711. 'Tried to join the shuttle', /* sInitialSituation */
  2712. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2713. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2714. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2715. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2716. 'sub product of the service', /* sProduct */
  2717. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2718. array(
  2719. ), /* aImpact */
  2720. '6', /* sImpact */
  2721. '7', /* sUrgency */
  2722. ),
  2723. ),
  2724. array(
  2725. 'service_category' => '',
  2726. 'verb' => 'CreateIncidentTicket',
  2727. 'expected result' => false,
  2728. 'explain result' => 'wrong password',
  2729. 'args' => array(
  2730. 'admin', /* sLogin */
  2731. 'xxxxx', /* sPassword */
  2732. 'Houston not reachable', /* sDescription */
  2733. 'Tried to join the shuttle', /* sInitialSituation */
  2734. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2735. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2736. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2737. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2738. 'sub product of the service', /* sProduct */
  2739. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2740. array(
  2741. ), /* aImpact */
  2742. '1', /* sImpact */
  2743. '1', /* sUrgency */
  2744. ),
  2745. ),
  2746. array(
  2747. 'service_category' => '',
  2748. 'verb' => 'CreateIncidentTicket',
  2749. 'expected result' => false,
  2750. 'explain result' => 'wrong login',
  2751. 'args' => array(
  2752. 'xxxxx', /* sLogin */
  2753. 'yyyyy', /* sPassword */
  2754. 'Houston not reachable', /* sDescription */
  2755. 'Tried to join the shuttle', /* sInitialSituation */
  2756. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2757. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2758. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2759. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2760. 'sub product of the service', /* sProduct */
  2761. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2762. array(
  2763. ), /* aImpact */
  2764. '1', /* sImpact */
  2765. '1', /* sUrgency */
  2766. ),
  2767. ),
  2768. array(
  2769. 'service_category' => '',
  2770. 'verb' => 'SearchObjects',
  2771. 'expected result' => true,
  2772. 'explain result' => '',
  2773. 'args' => array(
  2774. 'admin', /* sLogin */
  2775. 'admin', /* sPassword */
  2776. 'SELECT Incident WHERE id > 20', /* sOQL */
  2777. ),
  2778. ),
  2779. array(
  2780. 'service_category' => '',
  2781. 'verb' => 'SearchObjects',
  2782. 'expected result' => false,
  2783. 'explain result' => 'wrong OQL',
  2784. 'args' => array(
  2785. 'admin', /* sLogin */
  2786. 'admin', /* sPassword */
  2787. 'SELECT ThisClassDoesNotExist', /* sOQL */
  2788. ),
  2789. ),
  2790. );
  2791. $aManageCloudUsersSpecs = array(
  2792. array(
  2793. 'service_category' => '',
  2794. 'verb' => 'SearchObjects',
  2795. 'expected result' => false,
  2796. 'explain result' => 'wrong OQL',
  2797. 'args' => array(
  2798. 'admin', /* sLogin */
  2799. 'admin', /* sPassword */
  2800. 'SELECT ThisClassDoesNotExist', /* sOQL */
  2801. ),
  2802. ),
  2803. array(
  2804. 'service_category' => '',
  2805. 'verb' => 'SearchObjects',
  2806. 'expected result' => true,
  2807. 'explain result' => 'ok',
  2808. 'args' => array(
  2809. 'admin', /* sLogin */
  2810. 'admin', /* sPassword */
  2811. 'SELECT Organization', /* sOQL */
  2812. ),
  2813. ),
  2814. array(
  2815. 'service_category' => 'CloudUsersManagementService',
  2816. 'verb' => 'CreateAccount',
  2817. 'expected result' => true,
  2818. 'explain result' => 'ok',
  2819. 'args' => array(
  2820. 'admin', /* sAdminLogin */
  2821. 'admin', /* sAdminPassword */
  2822. 'http://myserver.mydomain.fr:8080', /* sCloudMgrUrl */
  2823. 'andros@combodo.com', /* sLogin */
  2824. 'André', /* sFirstName */
  2825. 'Dupont', /* sLastName */
  2826. 1, /* iOrgId */
  2827. 'FR FR', /* sLanguage */
  2828. array(
  2829. array(
  2830. new SOAPKeyValue('profile_id', '2'),
  2831. new SOAPKeyValue('reason', 'whynot'),
  2832. ),
  2833. array(
  2834. new SOAPKeyValue('profile_id', '3'),
  2835. new SOAPKeyValue('reason', 'because'),
  2836. ),
  2837. ), /* aProfiles (array of key/value pairs) */
  2838. array(
  2839. ), /* aAllowedOrgs (array of key/value pairs) */
  2840. 'comment on the creation operation', /* sComment */
  2841. ),
  2842. ),
  2843. array(
  2844. 'service_category' => 'CloudUsersManagementService',
  2845. 'verb' => 'ModifyAccount',
  2846. 'expected result' => true,
  2847. 'explain result' => 'ok',
  2848. 'args' => array(
  2849. 'admin', /* sAdminLogin */
  2850. 'admin', /* sAdminPassword */
  2851. 'andros@combodo.com', /* sLogin */
  2852. 'nono', /* sFirstName */
  2853. 'robot', /* sLastName */
  2854. 2, /* iOrgId */
  2855. 'EN US', /* sLanguage */
  2856. array(
  2857. array(
  2858. new SOAPKeyValue('profile_id', '3'),
  2859. new SOAPKeyValue('reason', 'because'),
  2860. ),
  2861. ), /* aProfiles (array of key/value pairs) */
  2862. array(
  2863. ), /* aAllowedOrgs (array of key/value pairs) */
  2864. 'comment on the modify operation', /* sComment */
  2865. ),
  2866. ),
  2867. array(
  2868. 'service_category' => 'CloudUsersManagementService',
  2869. 'verb' => 'DeleteAccount',
  2870. 'expected result' => true,
  2871. 'explain result' => '',
  2872. 'args' => array(
  2873. 'admin', /* sAdminLogin */
  2874. 'admin', /* sAdminPassword */
  2875. 'andros@combodo.com', /* sLogin */
  2876. 'comment on the deletion operation', /* sComment */
  2877. ),
  2878. ),
  2879. array(
  2880. 'service_category' => 'CloudUsersManagementService',
  2881. 'verb' => 'DeleteAccount',
  2882. 'expected result' => false,
  2883. 'explain result' => 'wrong login',
  2884. 'args' => array(
  2885. 'admin', /* sAdminLogin */
  2886. 'admin', /* sAdminPassword */
  2887. 'taratatata@sdf.com', /* sLogin */
  2888. 'comment on the deletion operation', /* sComment */
  2889. ),
  2890. ),
  2891. );
  2892. abstract class TestSoap extends TestSoapWebService
  2893. {
  2894. static public function GetName() {return 'Test SOAP';}
  2895. static public function GetDescription() {return 'Do basic stuff to test the SOAP capability';}
  2896. protected $m_aTestSpecs;
  2897. protected function DoExecute()
  2898. {
  2899. echo "<p>Note: You may also want to try the sample SOAP client <a href=\"../webservices/itopsoap.examples.php\">itopsoap.examples.php</a></p>\n";
  2900. $aSOAPMapping = SOAPMapping::GetMapping();
  2901. // this file is generated dynamically with location = here
  2902. $sWsdlUri = 'http'.(utils::IsConnectionSecure() ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../webservices/itop.wsdl.php';
  2903. ini_set("soap.wsdl_cache_enabled","0");
  2904. foreach ($this->m_aTestSpecs as $iPos => $aWebService)
  2905. {
  2906. echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
  2907. echo "<p>Using WSDL: $sWsdlUriForService</p>\n";
  2908. echo "<p>{$aWebService['explain result']}</p>\n";
  2909. $sWsdlUriForService = $sWsdlUri.'?service_category='.$aWebService['service_category'];
  2910. $this->m_SoapClient = new SoapClient
  2911. (
  2912. $sWsdlUriForService,
  2913. array(
  2914. 'classmap' => $aSOAPMapping,
  2915. 'trace' => 1,
  2916. )
  2917. );
  2918. if (false)
  2919. {
  2920. self::DumpVariable($this->m_SoapClient->__getTypes());
  2921. }
  2922. try
  2923. {
  2924. $oRes = call_user_func_array(array($this->m_SoapClient, $aWebService['verb']), $aWebService['args']);
  2925. }
  2926. catch(SoapFault $e)
  2927. {
  2928. print "<pre>\n";
  2929. print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n";
  2930. print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n";
  2931. print "</pre>";
  2932. print "Response in HTML: <p>".$this->m_SoapClient->__getLastResponse()."</p>";
  2933. throw $e;
  2934. }
  2935. self::DumpVariable($oRes);
  2936. print "<pre>\n";
  2937. print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n";
  2938. print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n";
  2939. print "</pre>";
  2940. if ($oRes instanceof SOAPResult)
  2941. {
  2942. $res = $oRes->status;
  2943. }
  2944. elseif ($oRes instanceof SOAPSimpleResult)
  2945. {
  2946. $res = $oRes->status;
  2947. }
  2948. else
  2949. {
  2950. $res = $oRes;
  2951. }
  2952. if ($res != $aWebService['expected result'])
  2953. {
  2954. echo "Expecting:<br/>\n";
  2955. var_dump($aWebService['expected result']);
  2956. echo "Obtained:<br/>\n";
  2957. var_dump($res);
  2958. throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  2959. }
  2960. }
  2961. }
  2962. }
  2963. abstract class TestSoapDirect extends TestBizModel
  2964. {
  2965. static public function GetName() {return 'Test web services locally';}
  2966. static public function GetDescription() {return 'Invoke the service directly (troubleshooting)';}
  2967. protected $m_aTestSpecs;
  2968. protected function DoExecute()
  2969. {
  2970. foreach ($this->m_aTestSpecs as $iPos => $aWebService)
  2971. {
  2972. $sServiceClass = $aWebService['service_category'];
  2973. if (empty($sServiceClass)) $sServiceClass = 'BasicServices';
  2974. $oWebServices = new $sServiceClass();
  2975. echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
  2976. echo "<p>{$aWebService['explain result']}</p>\n";
  2977. $oRes = call_user_func_array(array($oWebServices, $aWebService['verb']), $aWebService['args']);
  2978. self::DumpVariable($oRes);
  2979. if ($oRes instanceof SOAPResult)
  2980. {
  2981. $res = $oRes->status;
  2982. }
  2983. elseif ($oRes instanceof SOAPSimpleResult)
  2984. {
  2985. $res = $oRes->status;
  2986. }
  2987. else
  2988. {
  2989. $res = $oRes;
  2990. }
  2991. if ($res != $aWebService['expected result'])
  2992. {
  2993. echo "Expecting:<br/>\n";
  2994. var_dump($aWebService['expected result']);
  2995. echo "Obtained:<br/>\n";
  2996. var_dump($res);
  2997. throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  2998. }
  2999. }
  3000. return true;
  3001. }
  3002. }
  3003. class TestSoap_Tickets extends TestSoap
  3004. {
  3005. static public function GetName() {return 'Test SOAP - create ticket';}
  3006. protected function DoExecute()
  3007. {
  3008. global $aCreateTicketSpecs;
  3009. $this->m_aTestSpecs = $aCreateTicketSpecs;
  3010. return parent::DoExecute();
  3011. }
  3012. }
  3013. class TestSoapDirect_Tickets extends TestSoapDirect
  3014. {
  3015. static public function GetName() {return 'Test SOAP without SOAP - create ticket';}
  3016. protected function DoExecute()
  3017. {
  3018. global $aCreateTicketSpecs;
  3019. $this->m_aTestSpecs = $aCreateTicketSpecs;
  3020. return parent::DoExecute();
  3021. }
  3022. }
  3023. class TestSoap_ManageCloudUsers extends TestSoap
  3024. {
  3025. static public function GetName() {return 'Test SOAP - manage Cloud Users';}
  3026. protected function DoExecute()
  3027. {
  3028. global $aManageCloudUsersSpecs;
  3029. $this->m_aTestSpecs = $aManageCloudUsersSpecs;
  3030. return parent::DoExecute();
  3031. }
  3032. }
  3033. class TestSoapDirect_ManageCloudUsers extends TestSoapDirect
  3034. {
  3035. static public function GetName() {return 'Test SOAP without SOAP - manage Cloud Users';}
  3036. protected function DoExecute()
  3037. {
  3038. global $aManageCloudUsersSpecs;
  3039. $this->m_aTestSpecs = $aManageCloudUsersSpecs;
  3040. return parent::DoExecute();
  3041. }
  3042. }
  3043. ////////////////////// End of SOAP TESTS
  3044. class TestTriggerAndEmail extends TestBizModel
  3045. {
  3046. static public function GetName() {return 'Test trigger and email';}
  3047. static public function GetDescription() {return 'Create a trigger and an email, then activates the trigger';}
  3048. protected function CreateEmailSpec($oTrigger, $sStatus, $sTo, $sCC, $sTesterEmail)
  3049. {
  3050. $oAction = MetaModel::NewObject("ActionEmail");
  3051. $oAction->Set("status", $sStatus);
  3052. $oAction->Set("name", "New server");
  3053. $oAction->Set("test_recipient", $sTesterEmail);
  3054. $oAction->Set("from", $sTesterEmail);
  3055. $oAction->Set("reply_to", $sTesterEmail);
  3056. $oAction->Set("to", $sTo);
  3057. $oAction->Set("cc", $sCC);
  3058. $oAction->Set("bcc", "");
  3059. $oAction->Set("subject", "New server: '\$this->name()$'");
  3060. $oAction->Set("body", "<html><body><p>Dear customer,</p><p>We have created the server \$this->hyperlink()$ in the IT infrastructure database.</p><p>You will be further notified when it is in <strong>Production</strong>.</p><p>The IT infrastructure management team.</p><p>Here are some accentuated characters for french people: 'ééà'</p></body></html>");
  3061. $oAction->Set("importance", "low");
  3062. $iActionId = $this->ObjectToDB($oAction, true);
  3063. $oLink = MetaModel::NewObject("lnkTriggerAction");
  3064. $oLink->Set("trigger_id", $oTrigger->GetKey());
  3065. $oLink->Set("action_id", $iActionId);
  3066. $oLink->Set("order", "1");
  3067. $iLink = $this->ObjectToDB($oLink, true);
  3068. }
  3069. protected function DoExecute()
  3070. {
  3071. $oMyPerson = MetaModel::NewObject("Person");
  3072. $oMyPerson->Set("name", "testemail1");
  3073. $oMyPerson->Set("first_name", "theodore");
  3074. $oMyPerson->Set("org_id", "1");
  3075. $oMyPerson->Set("email", "romain.quetiez@combodo.com");
  3076. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  3077. $oMyPerson = MetaModel::NewObject("Person");
  3078. $oMyPerson->Set("name", "testemail2");
  3079. $oMyPerson->Set("first_name", "theodore");
  3080. $oMyPerson->Set("org_id", "1");
  3081. $oMyPerson->Set("email", "denis.flaven@combodo.com");
  3082. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  3083. $oMyPerson = MetaModel::NewObject("Person");
  3084. $oMyPerson->Set("name", "testemail3");
  3085. $oMyPerson->Set("first_name", "theodore");
  3086. $oMyPerson->Set("org_id", "1");
  3087. $oMyPerson->Set("email", "erwan.taloc@combodo.com");
  3088. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  3089. $oMyServer = MetaModel::NewObject("Server");
  3090. $oMyServer->Set("name", "wfr.terminator.com");
  3091. $oMyServer->Set("status", "production");
  3092. $oMyServer->Set("org_id", 2);
  3093. $iServerId = $this->ObjectToDB($oMyServer, true);
  3094. $oMyTrigger = MetaModel::NewObject("TriggerOnStateEnter");
  3095. $oMyTrigger->Set("description", "Testor");
  3096. $oMyTrigger->Set("target_class", "Server");
  3097. $oMyTrigger->Set("state", "Shipped");
  3098. $iTriggerId = $this->ObjectToDB($oMyTrigger, true);
  3099. // Error in OQL field(s)
  3100. //
  3101. $this->CreateEmailSpec
  3102. (
  3103. $oMyTrigger,
  3104. 'test',
  3105. "SELECT Person WHERE naime = 'Dali'",
  3106. "SELECT Server",
  3107. 'romain.quetiez@combodo.com'
  3108. );
  3109. // Error: no recipient
  3110. //
  3111. $this->CreateEmailSpec
  3112. (
  3113. $oMyTrigger,
  3114. 'test',
  3115. "",
  3116. "",
  3117. 'romain.quetiez@combodo.com'
  3118. );
  3119. // Test
  3120. //
  3121. $this->CreateEmailSpec
  3122. (
  3123. $oMyTrigger,
  3124. 'test',
  3125. "SELECT Person WHERE name LIKE 'testemail%'",
  3126. "SELECT Person",
  3127. 'romain.quetiez@combodo.com'
  3128. );
  3129. // Test failing because of a wrong test recipient address
  3130. //
  3131. $this->CreateEmailSpec
  3132. (
  3133. $oMyTrigger,
  3134. 'test',
  3135. "SELECT Person WHERE name LIKE 'testemail%'",
  3136. "",
  3137. 'toto@walibi.bg'
  3138. );
  3139. // Normal behavior
  3140. //
  3141. $this->CreateEmailSpec
  3142. (
  3143. $oMyTrigger,
  3144. 'enabled',
  3145. "SELECT Person WHERE name LIKE 'testemail%'",
  3146. "",
  3147. 'romain.quetiez@combodo.com'
  3148. );
  3149. // Does nothing, because it is disabled
  3150. //
  3151. $this->CreateEmailSpec
  3152. (
  3153. $oMyTrigger,
  3154. 'disabled',
  3155. "SELECT Person WHERE name = 'testemail%'",
  3156. "",
  3157. 'romain.quetiez@combodo.com'
  3158. );
  3159. $oMyTrigger->DoActivate($oMyServer->ToArgs('this'));
  3160. return true;
  3161. }
  3162. }
  3163. class TestDBProperties extends TestBizModel
  3164. {
  3165. static public function GetName()
  3166. {
  3167. return 'Itop - DB Properties';
  3168. }
  3169. static public function GetDescription()
  3170. {
  3171. return 'Write and read a dummy property';
  3172. }
  3173. protected function DoExecute()
  3174. {
  3175. $sName = 'test';
  3176. DBProperty::SetProperty($sName, 'unix time:'.time(), 'means nothing', 'done with the automated test utility');
  3177. $sValue = DBProperty::GetProperty($sName, 'defaults to this because the table has not been created (1.0.1 install?)');
  3178. echo "<p>Write... then read property <b>$sName</b>, found: '$sValue'</p>\n";
  3179. }
  3180. }
  3181. class TestCreateObjects extends TestBizModel
  3182. {
  3183. static public function GetName()
  3184. {
  3185. return 'Itop - create objects';
  3186. }
  3187. static public function GetDescription()
  3188. {
  3189. return 'Create weird objects (reproduce a bug?)';
  3190. }
  3191. protected function DoExecute()
  3192. {
  3193. $oMyObj = MetaModel::NewObject("Server");
  3194. $oMyObj->Set("name", "test".rand(1,1000));
  3195. $oMyObj->Set("org_id", 2);
  3196. $oMyObj->Set("status", 'production');
  3197. $this->ObjectToDB($oMyObj, $bReload = true);
  3198. echo "<p>Created: {$oMyObj->GetHyperLink()}</p>";
  3199. $sTicketRef = "I-abcdef";
  3200. echo "<p>Creating: $sTicketRef</p>";
  3201. $oMyObj = MetaModel::NewObject("Incident");
  3202. $oMyObj->Set("ref", $sTicketRef);
  3203. $oMyObj->Set("title", "my title");
  3204. $oMyObj->Set("description", "my description");
  3205. $oMyObj->Set("ticket_log", "my ticket log");
  3206. $oMyObj->Set("start_date", "2010-03-08 17:37:00");
  3207. $oMyObj->Set("status", "resolved");
  3208. $oMyObj->Set("caller_id", 1);
  3209. $oMyObj->Set("org_id", 1);
  3210. $oMyObj->Set("urgency", 3);
  3211. $oMyObj->Set("agent_id", 1);
  3212. $oMyObj->Set("close_date", "0000-00-00 00:00:00");
  3213. $oMyObj->Set("last_update", "2010-04-08 16:47:29");
  3214. $oMyObj->Set("solution", "branche ton pc!");
  3215. // External key given as a string -> should be casted to an integer
  3216. $oMyObj->Set("service_id", "1");
  3217. $oMyObj->Set("servicesubcategory_id", "1");
  3218. $oMyObj->Set("product", "");
  3219. $oMyObj->Set("impact", 2);
  3220. $oMyObj->Set("priority", 3);
  3221. $oMyObj->Set("related_problem_id", 0);
  3222. $oMyObj->Set("related_change_id", 0);
  3223. $oMyObj->Set("assignment_date", "");
  3224. $oMyObj->Set("resolution_date", "");
  3225. $oMyObj->Set("tto_escalation_deadline", "");
  3226. $oMyObj->Set("ttr_escalation_deadline", "");
  3227. $oMyObj->Set("closure_deadline", "");
  3228. $oMyObj->Set("resolution_code", "fixed");
  3229. $oMyObj->Set("user_satisfaction", "");
  3230. $oMyObj->Set("user_commment", "");
  3231. $oMyObj->Set("workgroup_id", 4);
  3232. $this->ObjectToDB($oMyObj, $bReload = true);
  3233. echo "<p>Created: {$oMyObj->GetHyperLink()}</p>";
  3234. }
  3235. }
  3236. class TestSetLinkset extends TestBizModel
  3237. {
  3238. static public function GetName()
  3239. {
  3240. return 'Itop - Link set from a string';
  3241. }
  3242. static public function GetDescription()
  3243. {
  3244. return 'Create a user account, setting its profile by the mean of a string (prerequisite to CSV import of linksets)';
  3245. }
  3246. protected function DoExecute()
  3247. {
  3248. $oUser = new UserLocal();
  3249. $oUser->Set('login', 'patator'.time());
  3250. $oUser->Set('password', 'patator');
  3251. //$oUser->Set('contactid', 0);
  3252. //$oUser->Set('language', $sLanguage);
  3253. $sLinkSetSpec = "profileid:10;reason:service manager|profileid->name:Problem Manager;'reason:problem manager;glandeur";
  3254. $oAttDef = MetaModel::GetAttributeDef('UserLocal', 'profile_list');
  3255. $oSet = $oAttDef->MakeValueFromString($sLinkSetSpec, $bLocalizedValue = false);
  3256. $oUser->Set('profile_list', $oSet);
  3257. // Create a change to record the history of the User object
  3258. $this->ObjectToDB($oUser, $bReload = true);
  3259. echo "<p>Created: {$oUser->GetHyperLink()}</p>";
  3260. }
  3261. }
  3262. class TestEmailAsynchronous extends TestBizModel
  3263. {
  3264. static public function GetName()
  3265. {
  3266. return 'Itop - Asynchronous email';
  3267. }
  3268. static public function GetDescription()
  3269. {
  3270. return 'Queues a request to send an email';
  3271. }
  3272. protected function DoExecute()
  3273. {
  3274. for ($i = 0 ; $i < 2 ; $i++)
  3275. {
  3276. $oMail = new Email();
  3277. $oMail->SetRecipientTO('romain.quetiez@combodo.com');
  3278. $oMail->SetRecipientFrom('romain.quetiez@combodo.com');
  3279. $oMail->SetRecipientCC('romainquetiez@yahoo.fr');
  3280. $oMail->SetSubject('automated test - '.$i);
  3281. $oMail->SetBody('this is one is entirely working fine '.time());
  3282. $iRes = $oMail->Send($aIssues, false);
  3283. switch ($iRes)
  3284. {
  3285. case EMAIL_SEND_OK:
  3286. echo "EMAIL_SEND_OK<br/>\n";
  3287. break;
  3288. case EMAIL_SEND_PENDING:
  3289. echo "EMAIL_SEND_PENDING<br/>\n";
  3290. break;
  3291. case EMAIL_SEND_ERROR:
  3292. echo "EMAIL_SEND_ERROR: <br/>\n";
  3293. foreach($aIssues as $sIssue)
  3294. {
  3295. echo "Issue: $sIssue<br/>\n";
  3296. }
  3297. break;
  3298. }
  3299. }
  3300. }
  3301. }
  3302. abstract class TestLinkSet extends TestBizModel
  3303. {
  3304. protected function StandardizedDump($oSet, $sAttPrefixToIgnore)
  3305. {
  3306. if (!$oSet->m_bLoaded) $oSet->Load();
  3307. $oSet->Rewind();
  3308. $aRet = array();
  3309. while($oObject = $oSet->Fetch())
  3310. {
  3311. $aValues = array();
  3312. foreach(MetaModel::ListAttributeDefs(get_class($oObject)) as $sAttCode => $oAttDef)
  3313. {
  3314. //if (!$oAttDef->IsPartOfFingerprint()) continue;
  3315. //if ($oAttDef->IsMagic()) continue;
  3316. if ($sAttCode == 'friendlyname') continue;
  3317. if (substr($sAttCode, -strlen('_archive_flag')) == '_archive_flag') continue;
  3318. if (substr($sAttCode, -strlen('_obsolescence_flag')) == '_obsolescence_flag') continue;
  3319. if (substr($sAttCode, 0, strlen($sAttPrefixToIgnore)) == $sAttPrefixToIgnore) continue;
  3320. if ($oAttDef->IsScalar())
  3321. {
  3322. $aValues[] = $oObject->Get($sAttCode);
  3323. }
  3324. }
  3325. $aRet[] = implode(', ', $aValues);
  3326. }
  3327. sort($aRet);
  3328. return $aRet;
  3329. }
  3330. }
  3331. class TestLinkSetRecording_NN_WithDuplicates extends TestLinkSet
  3332. {
  3333. static public function GetName()
  3334. {
  3335. return 'Linkset N-N having duplicated allowed (Connectable CI to Network Device)';
  3336. }
  3337. static public function GetDescription()
  3338. {
  3339. return 'Simulate CSV/data synchro type of recording. Check the values and the history. Lots of issues there: #1145, #1146 and #1147';
  3340. }
  3341. protected function DoExecute()
  3342. {
  3343. CMDBSource::Query('START TRANSACTION');
  3344. //CMDBSource::Query('ROLLBACK'); automatique !
  3345. ////////////////////////////////////////////////////////////////////////////////
  3346. // Set the stage
  3347. //
  3348. $oServer = MetaModel::NewObject('Server');
  3349. $oServer->Set('name', 'unit test linkset');
  3350. $oServer->Set('org_id', 3);
  3351. $oServer->DBInsert();
  3352. $iServer = $oServer->GetKey();
  3353. $oTypes = new DBObjectSet(DBObjectSearch::FromOQL('SELECT NetworkDeviceType WHERE name = "Router"'));
  3354. $oType = $oTypes->fetch();
  3355. $oDevice = MetaModel::NewObject('NetworkDevice');
  3356. $oDevice->Set('name', 'test device A');
  3357. $oDevice->Set('org_id', 3);
  3358. $oDevice->Set('networkdevicetype_id', $oType->GetKey());
  3359. $oDevice->DBInsert();
  3360. $iDev1 = $oDevice->GetKey();
  3361. $oDevice = MetaModel::NewObject('NetworkDevice');
  3362. $oDevice->Set('name', 'test device B');
  3363. $oDevice->Set('org_id', 3);
  3364. $oDevice->Set('networkdevicetype_id', $oType->GetKey());
  3365. $oDevice->DBInsert();
  3366. $iDev2 = $oDevice->GetKey();
  3367. ////////////////////////////////////////////////////////////////////////////////
  3368. // Scenarii
  3369. //
  3370. $aScenarii = array(
  3371. array(
  3372. 'description' => 'Add the first item',
  3373. 'links' => array(
  3374. array(
  3375. 'networkdevice_id' => $iDev1,
  3376. 'connectableci_id' => $iServer,
  3377. 'network_port' => '',
  3378. 'device_port' => '',
  3379. ),
  3380. ),
  3381. 'expected-res' => array (
  3382. "$iDev1, test device A, unit test linkset, , , downlink, test device A",
  3383. ),
  3384. 'history_added' => 1,
  3385. 'history_removed' => 0,
  3386. 'history_modified' => 0,
  3387. ),
  3388. array(
  3389. 'description' => 'Modify the unique item',
  3390. 'links' => array(
  3391. array(
  3392. 'networkdevice_id' => $iDev1,
  3393. 'connectableci_id' => $iServer,
  3394. 'network_port' => 'devTagada',
  3395. 'device_port' => '',
  3396. ),
  3397. ),
  3398. 'expected-res' => array (
  3399. "$iDev1, test device A, unit test linkset, devTagada, , downlink, test device A",
  3400. ),
  3401. 'history_added' => 1,
  3402. 'history_removed' => 1,
  3403. 'history_modified' => 0,
  3404. ),
  3405. array(
  3406. 'description' => 'Modify again the original item and add a second item',
  3407. 'links' => array(
  3408. array(
  3409. 'networkdevice_id' => $iDev1,
  3410. 'connectableci_id' => $iServer,
  3411. 'network_port' => '',
  3412. 'device_port' => '',
  3413. ),
  3414. array(
  3415. 'networkdevice_id' => $iDev2,
  3416. 'connectableci_id' => $iServer,
  3417. 'network_port' => '',
  3418. 'device_port' => '',
  3419. ),
  3420. ),
  3421. 'expected-res' => array (
  3422. "$iDev1, test device A, unit test linkset, , , downlink, test device A",
  3423. "$iDev2, test device B, unit test linkset, , , downlink, test device B",
  3424. ),
  3425. 'history_added' => 2,
  3426. 'history_removed' => 1,
  3427. 'history_modified' => 0,
  3428. ),
  3429. array(
  3430. 'description' => 'No change, the links are added in the reverse order',
  3431. 'links' => array(
  3432. array(
  3433. 'networkdevice_id' => $iDev2,
  3434. 'connectableci_id' => $iServer,
  3435. 'network_port' => '',
  3436. 'device_port' => '',
  3437. ),
  3438. array(
  3439. 'networkdevice_id' => $iDev1,
  3440. 'connectableci_id' => $iServer,
  3441. 'network_port' => '',
  3442. 'device_port' => '',
  3443. ),
  3444. ),
  3445. 'expected-res' => array (
  3446. "$iDev1, test device A, unit test linkset, , , downlink, test device A",
  3447. "$iDev2, test device B, unit test linkset, , , downlink, test device B",
  3448. ),
  3449. 'history_added' => 0,
  3450. 'history_removed' => 0,
  3451. 'history_modified' => 0,
  3452. ),
  3453. array(
  3454. 'description' => 'Change on attribute on both links at the same time',
  3455. 'links' => array(
  3456. array(
  3457. 'networkdevice_id' => $iDev2,
  3458. 'connectableci_id' => $iServer,
  3459. 'network_port' => 'PortDev B',
  3460. 'device_port' => '',
  3461. ),
  3462. array(
  3463. 'networkdevice_id' => $iDev1,
  3464. 'connectableci_id' => $iServer,
  3465. 'network_port' => 'PortDev A',
  3466. 'device_port' => '',
  3467. ),
  3468. ),
  3469. 'expected-res' => array (
  3470. "$iDev1, test device A, unit test linkset, PortDev A, , downlink, test device A",
  3471. "$iDev2, test device B, unit test linkset, PortDev B, , downlink, test device B",
  3472. ),
  3473. 'history_added' => 2,
  3474. 'history_removed' => 2,
  3475. 'history_modified' => 0,
  3476. ),
  3477. array(
  3478. 'description' => 'Removing A',
  3479. 'links' => array(
  3480. array(
  3481. 'networkdevice_id' => $iDev2,
  3482. 'connectableci_id' => $iServer,
  3483. 'network_port' => 'PortDev B',
  3484. 'device_port' => '',
  3485. ),
  3486. ),
  3487. 'expected-res' => array (
  3488. "$iDev2, test device B, unit test linkset, PortDev B, , downlink, test device B",
  3489. ),
  3490. 'history_added' => 0,
  3491. 'history_removed' => 1,
  3492. 'history_modified' => 0,
  3493. ),
  3494. array(
  3495. 'description' => 'Adding B again - with a different port (duplicate!)',
  3496. 'links' => array(
  3497. array(
  3498. 'networkdevice_id' => $iDev2,
  3499. 'connectableci_id' => $iServer,
  3500. 'network_port' => 'port_123',
  3501. 'device_port' => '',
  3502. ),
  3503. array(
  3504. 'networkdevice_id' => $iDev2,
  3505. 'connectableci_id' => $iServer,
  3506. 'network_port' => 'port_456',
  3507. 'device_port' => '',
  3508. ),
  3509. ),
  3510. 'expected-res' => array (
  3511. "$iDev2, test device B, unit test linkset, port_123, , downlink, test device B",
  3512. "$iDev2, test device B, unit test linkset, port_456, , downlink, test device B",
  3513. ),
  3514. 'history_added' => 2,
  3515. 'history_removed' => 1,
  3516. 'history_modified' => 0,
  3517. ),
  3518. array(
  3519. 'description' => 'No change (creating a set with the reloaded links, like in the UI)',
  3520. 'links' => array(
  3521. array(
  3522. 'id' => "SELECT lnkConnectableCIToNetworkDevice WHERE networkdevice_id = $iDev2 AND connectableci_id = $iServer AND network_port = 'port_123'",
  3523. 'networkdevice_id' => $iDev2,
  3524. 'connectableci_id' => $iServer,
  3525. 'network_port' => 'port_123',
  3526. 'device_port' => '',
  3527. ),
  3528. array(
  3529. 'id' => "SELECT lnkConnectableCIToNetworkDevice WHERE networkdevice_id = $iDev2 AND connectableci_id = $iServer AND network_port = 'port_456'",
  3530. 'networkdevice_id' => $iDev2,
  3531. 'connectableci_id' => $iServer,
  3532. 'network_port' => 'port_456',
  3533. 'device_port' => '',
  3534. ),
  3535. ),
  3536. 'expected-res' => array (
  3537. "$iDev2, test device B, unit test linkset, port_123, , downlink, test device B",
  3538. "$iDev2, test device B, unit test linkset, port_456, , downlink, test device B",
  3539. ),
  3540. 'history_added' => 0,
  3541. 'history_removed' => 0,
  3542. 'history_modified' => 0,
  3543. ),
  3544. array(
  3545. 'description' => 'Change an attribute on one link (based on reloaded links, like in the UI)',
  3546. 'links' => array(
  3547. array(
  3548. 'id' => "SELECT lnkConnectableCIToNetworkDevice WHERE networkdevice_id = $iDev2 AND connectableci_id = $iServer AND network_port = 'port_123'",
  3549. 'networkdevice_id' => $iDev2,
  3550. 'connectableci_id' => $iServer,
  3551. 'network_port' => 'port_123_modified',
  3552. 'device_port' => '',
  3553. ),
  3554. array(
  3555. 'id' => "SELECT lnkConnectableCIToNetworkDevice WHERE networkdevice_id = $iDev2 AND connectableci_id = $iServer AND network_port = 'port_456'",
  3556. 'networkdevice_id' => $iDev2,
  3557. 'connectableci_id' => $iServer,
  3558. 'network_port' => 'port_456',
  3559. 'device_port' => '',
  3560. ),
  3561. ),
  3562. 'expected-res' => array (
  3563. "$iDev2, test device B, unit test linkset, port_123_modified, , downlink, test device B",
  3564. "$iDev2, test device B, unit test linkset, port_456, , downlink, test device B",
  3565. ),
  3566. 'history_added' => 0,
  3567. 'history_removed' => 0,
  3568. 'history_modified' => 1,
  3569. ),
  3570. array(
  3571. 'description' => 'Remove the second link (set based on reloaded links, like in the UI)',
  3572. 'links' => array(
  3573. array(
  3574. 'id' => "SELECT lnkConnectableCIToNetworkDevice WHERE networkdevice_id = $iDev2 AND connectableci_id = $iServer AND network_port = 'port_123_modified'",
  3575. 'networkdevice_id' => $iDev2,
  3576. 'connectableci_id' => $iServer,
  3577. 'network_port' => 'port_123_modified',
  3578. 'device_port' => '',
  3579. ),
  3580. ),
  3581. 'expected-res' => array (
  3582. "$iDev2, test device B, unit test linkset, port_123_modified, , downlink, test device B",
  3583. ),
  3584. 'history_added' => 0,
  3585. 'history_removed' => 1,
  3586. 'history_modified' => 0,
  3587. ),
  3588. array(
  3589. 'description' => 'Remove all',
  3590. 'links' => array(
  3591. ),
  3592. 'expected-res' => array (
  3593. ),
  3594. 'history_added' => 0,
  3595. 'history_removed' => 1,
  3596. 'history_modified' => 0,
  3597. ),
  3598. array(
  3599. 'description' => 'Create one link from scratch, no port, to prepare for the next test case',
  3600. 'links' => array(
  3601. array(
  3602. 'networkdevice_id' => $iDev2,
  3603. 'connectableci_id' => $iServer,
  3604. 'network_port' => 'portX',
  3605. 'device_port' => '',
  3606. ),
  3607. ),
  3608. 'expected-res' => array (
  3609. "$iDev2, test device B, unit test linkset, portX, , downlink, test device B",
  3610. ),
  3611. 'history_added' => 1,
  3612. 'history_removed' => 0,
  3613. 'history_modified' => 0,
  3614. ),
  3615. array(
  3616. 'description' => 'Device B twice (same characteristics) - known issue #1145 (test failing until we fix it)',
  3617. 'links' => array(
  3618. array(
  3619. 'networkdevice_id' => $iDev2,
  3620. 'connectableci_id' => $iServer,
  3621. 'network_port' => 'portX',
  3622. 'device_port' => '',
  3623. ),
  3624. array(
  3625. 'networkdevice_id' => $iDev2,
  3626. 'connectableci_id' => $iServer,
  3627. 'network_port' => 'portX',
  3628. 'device_port' => '',
  3629. ),
  3630. ),
  3631. 'expected-res' => array (
  3632. "$iDev2, test device B, unit test linkset, portX, , downlink, test device B",
  3633. "$iDev2, test device B, unit test linkset, portX, , downlink, test device B",
  3634. ),
  3635. 'history_added' => 1,
  3636. 'history_removed' => 0,
  3637. 'history_modified' => 0,
  3638. ),
  3639. );
  3640. foreach ($aScenarii as $aScenario)
  3641. {
  3642. echo "<h4>".$aScenario['description']."</h4>\n";
  3643. $oChange = MetaModel::NewObject("CMDBChange");
  3644. $oChange->Set("date", time());
  3645. $oChange->Set("userinfo", CMDBChange::GetCurrentUserName());
  3646. $oChange->Set("origin", 'custom-extension');
  3647. $oChange->DBInsert();
  3648. CMDBObject::SetCurrentChange($oChange);
  3649. $iChange = $oChange->GetKey();
  3650. // Prepare set
  3651. $oLinkset = DBObjectSet::FromScratch('lnkConnectableCIToNetworkDevice');
  3652. foreach ($aScenario['links'] as $aLinkData)
  3653. {
  3654. if (array_key_exists('id', $aLinkData))
  3655. {
  3656. $sOQL = $aLinkData['id'];
  3657. $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
  3658. $oLink1 = $oSet->Fetch();
  3659. if (!is_object($oLink1)) throw new Exception('Failed to find the lnkConnectableCIToNetworkDevice: '.$sOQL);
  3660. }
  3661. else
  3662. {
  3663. $oLink1 = MetaModel::NewObject('lnkConnectableCIToNetworkDevice');
  3664. }
  3665. foreach ($aLinkData as $sAttCode => $value)
  3666. {
  3667. if ($sAttCode == 'id') continue;
  3668. $oLink1->Set($sAttCode, $value);
  3669. }
  3670. $oLinkset->AddObject($oLink1);
  3671. }
  3672. // Write
  3673. $oServer = MetaModel::GetObject('Server', $iServer);
  3674. $oServer->Set('networkdevice_list', $oLinkset);
  3675. $oServer->DBWrite();
  3676. // Check Results
  3677. $bFoundIssue = false;
  3678. $oServer = MetaModel::GetObject('Server', $iServer);
  3679. $oLinkset = $oServer->Get('networkdevice_list');
  3680. $aRes = $this->StandardizedDump($oLinkset, 'connectableci_id');
  3681. $sRes = var_export($aRes, true);
  3682. echo "Found: <pre>".$sRes."</pre>\n";
  3683. $sExpectedRes = var_export($aScenario['expected-res'], true);
  3684. if ($sRes != $sExpectedRes)
  3685. {
  3686. $bFoundIssue = true;
  3687. echo "NOT COMPLIANT!!! Expecting: <pre>".$sExpectedRes."</pre>\n";
  3688. }
  3689. // Check History
  3690. $aQueryParams = array('change' => $iChange, 'objclass' => get_class($oServer), 'objkey' => $oServer->GetKey());
  3691. $oAdded = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'added'"), array(), $aQueryParams);
  3692. echo "added: ".$oAdded->Count()."<br/>\n";
  3693. if ($aScenario['history_added'] != $oAdded->Count())
  3694. {
  3695. $bFoundIssue = true;
  3696. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_added']."<br/>\n";
  3697. }
  3698. $oRemoved = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'removed'"), array(), $aQueryParams);
  3699. echo "removed: ".$oRemoved->Count()."<br/>\n";
  3700. if ($aScenario['history_removed'] != $oRemoved->Count())
  3701. {
  3702. $bFoundIssue = true;
  3703. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_removed']."<br/>\n";
  3704. }
  3705. $oModified = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksTune WHERE objclass = :objclass AND objkey = :objkey AND change = :change"), array(), $aQueryParams);
  3706. echo "modified: ".$oModified->Count()."<br/>\n";
  3707. if ($aScenario['history_modified'] != $oModified->Count())
  3708. {
  3709. $bFoundIssue = true;
  3710. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_modified']."<br/>\n";
  3711. }
  3712. if ($bFoundIssue)
  3713. {
  3714. throw new Exception('Stopping on failed scenario');
  3715. }
  3716. }
  3717. }
  3718. }
  3719. class TestLinkSetRecording_NN_NoDuplicates extends TestLinkSet
  3720. {
  3721. static public function GetName()
  3722. {
  3723. return 'Linksets N-N in general (99% of them)';
  3724. }
  3725. static public function GetDescription()
  3726. {
  3727. return 'Simulate CSV/data synchro type of recording. Check the values and the history.';
  3728. }
  3729. protected function DoExecute()
  3730. {
  3731. CMDBSource::Query('START TRANSACTION');
  3732. //CMDBSource::Query('ROLLBACK'); automatique !
  3733. ////////////////////////////////////////////////////////////////////////////////
  3734. // Set the stage
  3735. //
  3736. $oTeam = MetaModel::NewObject('Team');
  3737. $oTeam->Set('name', 'unit test linkset');
  3738. $oTeam->Set('org_id', 3);
  3739. $oTeam->DBInsert();
  3740. $iTeam = $oTeam->GetKey();
  3741. $oPerson = MetaModel::NewObject('Person');
  3742. $oPerson->Set('name', 'test person A');
  3743. $oPerson->Set('first_name', 'totoche');
  3744. $oPerson->Set('org_id', 3);
  3745. $oPerson->DBInsert();
  3746. $iPerson1 = $oPerson->GetKey();
  3747. $oPerson = MetaModel::NewObject('Person');
  3748. $oPerson->Set('name', 'test person B');
  3749. $oPerson->Set('first_name', 'totoche');
  3750. $oPerson->Set('org_id', 3);
  3751. $oPerson->DBInsert();
  3752. $iPerson2 = $oPerson->GetKey();
  3753. $oTypes = new DBObjectSet(DBSearch::FromOQL('SELECT ContactType WHERE name="Manager"'));
  3754. $iRole = $oTypes->Fetch()->GetKey();
  3755. ////////////////////////////////////////////////////////////////////////////////
  3756. // Scenarii
  3757. //
  3758. $aScenarii = array(
  3759. array(
  3760. 'description' => 'Add the first item',
  3761. 'links' => array(
  3762. array(
  3763. 'person_id' => $iPerson1,
  3764. 'team_id' => $iTeam,
  3765. 'role_id' => 0,
  3766. ),
  3767. ),
  3768. 'expected-res' => array (
  3769. "unit test linkset, $iPerson1, test person A, 0, , totoche test person A, ",
  3770. ),
  3771. 'history_added' => 1,
  3772. 'history_removed' => 0,
  3773. 'history_modified' => 0,
  3774. ),
  3775. array(
  3776. 'description' => 'Modify the unique item',
  3777. 'links' => array(
  3778. array(
  3779. 'person_id' => $iPerson1,
  3780. 'team_id' => $iTeam,
  3781. 'role_id' => $iRole,
  3782. ),
  3783. ),
  3784. 'expected-res' => array (
  3785. "unit test linkset, $iPerson1, test person A, $iRole, Manager, totoche test person A, Manager",
  3786. ),
  3787. 'history_added' => 0,
  3788. 'history_removed' => 0,
  3789. 'history_modified' => 1,
  3790. ),
  3791. array(
  3792. 'description' => 'Modify again the original item and add a second item',
  3793. 'links' => array(
  3794. array(
  3795. 'person_id' => $iPerson1,
  3796. 'team_id' => $iTeam,
  3797. 'role_id' => 0,
  3798. ),
  3799. array(
  3800. 'person_id' => $iPerson2,
  3801. 'team_id' => $iTeam,
  3802. 'role_id' => 0,
  3803. ),
  3804. ),
  3805. 'expected-res' => array (
  3806. "unit test linkset, $iPerson1, test person A, 0, , totoche test person A, ",
  3807. "unit test linkset, $iPerson2, test person B, 0, , totoche test person B, ",
  3808. ),
  3809. 'history_added' => 1,
  3810. 'history_removed' => 0,
  3811. 'history_modified' => 1,
  3812. ),
  3813. array(
  3814. 'description' => 'No change, the links are added in the reverse order',
  3815. 'links' => array(
  3816. array(
  3817. 'person_id' => $iPerson2,
  3818. 'team_id' => $iTeam,
  3819. 'role_id' => 0,
  3820. ),
  3821. array(
  3822. 'person_id' => $iPerson1,
  3823. 'team_id' => $iTeam,
  3824. 'role_id' => 0,
  3825. ),
  3826. ),
  3827. 'expected-res' => array (
  3828. "unit test linkset, $iPerson1, test person A, 0, , totoche test person A, ",
  3829. "unit test linkset, $iPerson2, test person B, 0, , totoche test person B, ",
  3830. ),
  3831. 'history_added' => 0,
  3832. 'history_removed' => 0,
  3833. 'history_modified' => 0,
  3834. ),
  3835. array(
  3836. 'description' => 'Removing A',
  3837. 'links' => array(
  3838. array(
  3839. 'person_id' => $iPerson2,
  3840. 'team_id' => $iTeam,
  3841. 'role_id' => 0,
  3842. ),
  3843. ),
  3844. 'expected-res' => array (
  3845. "unit test linkset, $iPerson2, test person B, 0, , totoche test person B, ",
  3846. ),
  3847. 'history_added' => 0,
  3848. 'history_removed' => 1,
  3849. 'history_modified' => 0,
  3850. ),
  3851. array(
  3852. 'description' => 'Adding B again (duplicate!)',
  3853. 'links' => array(
  3854. array(
  3855. 'person_id' => $iPerson2,
  3856. 'team_id' => $iTeam,
  3857. 'role_id' => 0,
  3858. ),
  3859. array(
  3860. 'person_id' => $iPerson2,
  3861. 'team_id' => $iTeam,
  3862. 'role_id' => 0,
  3863. ),
  3864. ),
  3865. 'expected-res' => array (
  3866. "unit test linkset, $iPerson2, test person B, 0, , totoche test person B, ",
  3867. ),
  3868. 'history_added' => 0,
  3869. 'history_removed' => 0,
  3870. 'history_modified' => 0,
  3871. ),
  3872. array(
  3873. 'description' => 'Remove all',
  3874. 'links' => array(
  3875. ),
  3876. 'expected-res' => array (
  3877. ),
  3878. 'history_added' => 0,
  3879. 'history_removed' => 1,
  3880. 'history_modified' => 0,
  3881. ),
  3882. array(
  3883. 'description' => 'Add the first item (again)',
  3884. 'links' => array(
  3885. array(
  3886. 'person_id' => $iPerson1,
  3887. 'team_id' => $iTeam,
  3888. 'role_id' => 0,
  3889. ),
  3890. ),
  3891. 'expected-res' => array (
  3892. "unit test linkset, $iPerson1, test person A, 0, , totoche test person A, ",
  3893. ),
  3894. 'history_added' => 1,
  3895. 'history_removed' => 0,
  3896. 'history_modified' => 0,
  3897. ),
  3898. array(
  3899. 'description' => 'Set the role (based on reloaded links, like in the UI)',
  3900. 'links' => array(
  3901. array(
  3902. 'id' => "SELECT lnkPersonToTeam WHERE person_id=$iPerson1 AND team_id=$iTeam",
  3903. 'person_id' => $iPerson1,
  3904. 'team_id' => $iTeam,
  3905. 'role_id' => $iRole,
  3906. ),
  3907. ),
  3908. 'expected-res' => array (
  3909. "unit test linkset, $iPerson1, test person A, 14, Manager, totoche test person A, Manager",
  3910. ),
  3911. 'history_added' => 0,
  3912. 'history_removed' => 0,
  3913. 'history_modified' => 1,
  3914. ),
  3915. array(
  3916. 'description' => 'Clear the role and add another person with a role (based on reloaded links, like in the UI)',
  3917. 'links' => array(
  3918. array(
  3919. 'id' => "SELECT lnkPersonToTeam WHERE person_id=$iPerson1 AND team_id=$iTeam",
  3920. 'person_id' => $iPerson1,
  3921. 'team_id' => $iTeam,
  3922. 'role_id' => 0,
  3923. ),
  3924. array(
  3925. 'person_id' => $iPerson2,
  3926. 'team_id' => $iTeam,
  3927. 'role_id' => $iRole,
  3928. ),
  3929. ),
  3930. 'expected-res' => array (
  3931. "unit test linkset, $iPerson1, test person A, 0, , totoche test person A, ",
  3932. "unit test linkset, $iPerson2, test person B, 14, Manager, totoche test person B, Manager",
  3933. ),
  3934. 'history_added' => 1,
  3935. 'history_removed' => 0,
  3936. 'history_modified' => 1,
  3937. ),
  3938. );
  3939. foreach ($aScenarii as $aScenario)
  3940. {
  3941. echo "<h4>".$aScenario['description']."</h4>\n";
  3942. $oChange = MetaModel::NewObject("CMDBChange");
  3943. $oChange->Set("date", time());
  3944. $oChange->Set("userinfo", CMDBChange::GetCurrentUserName());
  3945. $oChange->Set("origin", 'custom-extension');
  3946. $oChange->DBInsert();
  3947. CMDBObject::SetCurrentChange($oChange);
  3948. $iChange = $oChange->GetKey();
  3949. // Prepare set
  3950. $oLinkset = DBObjectSet::FromScratch('lnkPersonToTeam');
  3951. foreach ($aScenario['links'] as $aLinkData)
  3952. {
  3953. if (array_key_exists('id', $aLinkData))
  3954. {
  3955. $sOQL = $aLinkData['id'];
  3956. $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
  3957. $oLink1 = $oSet->Fetch();
  3958. if (!is_object($oLink1)) throw new Exception('Failed to find the lnkPersonToTeam: '.$sOQL);
  3959. }
  3960. else
  3961. {
  3962. $oLink1 = MetaModel::NewObject('lnkPersonToTeam');
  3963. }
  3964. foreach ($aLinkData as $sAttCode => $value)
  3965. {
  3966. if ($sAttCode == 'id') continue;
  3967. $oLink1->Set($sAttCode, $value);
  3968. }
  3969. $oLinkset->AddObject($oLink1);
  3970. }
  3971. // Write
  3972. $oTeam = MetaModel::GetObject('Team', $iTeam);
  3973. $oTeam->Set('persons_list', $oLinkset);
  3974. $oTeam->DBWrite();
  3975. // Check Results
  3976. $bFoundIssue = false;
  3977. $oTeam = MetaModel::GetObject('Team', $iTeam);
  3978. $oLinkset = $oTeam->Get('persons_list');
  3979. $aRes = $this->StandardizedDump($oLinkset, 'team_id');
  3980. $sRes = var_export($aRes, true);
  3981. echo "Found: <pre>".$sRes."</pre>\n";
  3982. $sExpectedRes = var_export($aScenario['expected-res'], true);
  3983. if ($sRes != $sExpectedRes)
  3984. {
  3985. $bFoundIssue = true;
  3986. echo "NOT COMPLIANT!!! Expecting: <pre>".$sExpectedRes."</pre>\n";
  3987. }
  3988. // Check History
  3989. $aQueryParams = array('change' => $iChange, 'objclass' => get_class($oTeam), 'objkey' => $oTeam->GetKey());
  3990. $oAdded = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'added'"), array(), $aQueryParams);
  3991. echo "added: ".$oAdded->Count()."<br/>\n";
  3992. if ($aScenario['history_added'] != $oAdded->Count())
  3993. {
  3994. $bFoundIssue = true;
  3995. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_added']."<br/>\n";
  3996. }
  3997. $oRemoved = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'removed'"), array(), $aQueryParams);
  3998. echo "removed: ".$oRemoved->Count()."<br/>\n";
  3999. if ($aScenario['history_removed'] != $oRemoved->Count())
  4000. {
  4001. $bFoundIssue = true;
  4002. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_removed']."<br/>\n";
  4003. }
  4004. $oModified = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksTune WHERE objclass = :objclass AND objkey = :objkey AND change = :change"), array(), $aQueryParams);
  4005. echo "modified: ".$oModified->Count()."<br/>\n";
  4006. if ($aScenario['history_modified'] != $oModified->Count())
  4007. {
  4008. $bFoundIssue = true;
  4009. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_modified']."<br/>\n";
  4010. }
  4011. if ($bFoundIssue)
  4012. {
  4013. throw new Exception('Stopping on failed scenario');
  4014. }
  4015. }
  4016. }
  4017. }
  4018. class TestLinkSetRecording_1N extends TestLinkSet
  4019. {
  4020. static public function GetName()
  4021. {
  4022. return 'Linkset 1-N (Network Interface vs Server: Edit in-place)';
  4023. }
  4024. static public function GetDescription()
  4025. {
  4026. return 'Simulate CSV/data synchro type of recording. Check the values and the history.';
  4027. }
  4028. protected function DoExecute()
  4029. {
  4030. CMDBSource::Query('START TRANSACTION');
  4031. //CMDBSource::Query('ROLLBACK'); automatique !
  4032. ////////////////////////////////////////////////////////////////////////////////
  4033. // Set the stage
  4034. //
  4035. $oServer = MetaModel::NewObject('Server');
  4036. $oServer->Set('name', 'unit test linkset');
  4037. $oServer->Set('org_id', 3);
  4038. $oServer->DBInsert();
  4039. $iServer = $oServer->GetKey();
  4040. ////////////////////////////////////////////////////////////////////////////////
  4041. // Scenarii
  4042. //
  4043. $aScenarii = array(
  4044. array(
  4045. 'description' => 'Add the first interface',
  4046. 'interfaces' => array(
  4047. array(
  4048. 'connectableci_id' => $iServer,
  4049. 'name' => 'eth0',
  4050. 'speed' => '1000.00',
  4051. ),
  4052. ),
  4053. 'expected-res' => array (
  4054. "eth0, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4055. ),
  4056. 'history_added' => 1,
  4057. 'history_removed' => 0,
  4058. 'history_modified' => 0,
  4059. ),
  4060. array(
  4061. 'description' => 'Add a second interface',
  4062. 'interfaces' => array(
  4063. array(
  4064. 'connectableci_id' => $iServer,
  4065. 'name' => 'eth0',
  4066. 'speed' => '1000.00',
  4067. ),
  4068. array(
  4069. 'connectableci_id' => $iServer,
  4070. 'name' => 'eth1',
  4071. 'speed' => '1000.00',
  4072. ),
  4073. ),
  4074. 'expected-res' => array (
  4075. "eth0, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4076. "eth1, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4077. ),
  4078. 'history_added' => 1,
  4079. 'history_removed' => 0,
  4080. 'history_modified' => 0,
  4081. ),
  4082. array(
  4083. 'description' => 'Change the speed of an interface',
  4084. 'interfaces' => array(
  4085. array(
  4086. 'connectableci_id' => $iServer,
  4087. 'name' => 'eth0',
  4088. 'speed' => '100.00',
  4089. ),
  4090. array(
  4091. 'connectableci_id' => $iServer,
  4092. 'name' => 'eth1',
  4093. 'speed' => '1000.00',
  4094. ),
  4095. ),
  4096. 'expected-res' => array (
  4097. "eth0, , , , , , 100.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4098. "eth1, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4099. ),
  4100. 'history_added' => 1,
  4101. 'history_removed' => 1,
  4102. 'history_modified' => 0,
  4103. ),
  4104. array(
  4105. 'description' => 'Change the name of an interface',
  4106. 'interfaces' => array(
  4107. array(
  4108. 'connectableci_id' => $iServer,
  4109. 'name' => 'eth0-renamed',
  4110. 'speed' => '1000.00',
  4111. ),
  4112. array(
  4113. 'connectableci_id' => $iServer,
  4114. 'name' => 'eth1',
  4115. 'speed' => '1000.00',
  4116. ),
  4117. ),
  4118. 'expected-res' => array (
  4119. "eth0-renamed, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4120. "eth1, , , , , , 1000.00, $iServer, unit test linkset, PhysicalInterface, unit test linkset, Server",
  4121. ),
  4122. 'history_added' => 1,
  4123. 'history_removed' => 1,
  4124. 'history_modified' => 0,
  4125. ),
  4126. array(
  4127. 'description' => 'Remove all interfaces',
  4128. 'interfaces' => array(
  4129. ),
  4130. 'expected-res' => array (
  4131. ),
  4132. 'history_added' => 0,
  4133. 'history_removed' => 2,
  4134. 'history_modified' => 0,
  4135. ),
  4136. );
  4137. foreach ($aScenarii as $aScenario)
  4138. {
  4139. echo "<h4>".$aScenario['description']."</h4>\n";
  4140. $oChange = MetaModel::NewObject("CMDBChange");
  4141. $oChange->Set("date", time());
  4142. $oChange->Set("userinfo", CMDBChange::GetCurrentUserName());
  4143. $oChange->Set("origin", 'custom-extension');
  4144. $oChange->DBInsert();
  4145. CMDBObject::SetCurrentChange($oChange);
  4146. $iChange = $oChange->GetKey();
  4147. // Prepare set
  4148. $oLinkset = DBObjectSet::FromScratch('PhysicalInterface');
  4149. foreach ($aScenario['interfaces'] as $aIntfData)
  4150. {
  4151. $oInterface = MetaModel::NewObject('PhysicalInterface');
  4152. foreach ($aIntfData as $sAttCode => $value)
  4153. {
  4154. $oInterface->Set($sAttCode, $value);
  4155. }
  4156. $oLinkset->AddObject($oInterface);
  4157. }
  4158. // Write
  4159. $oServer = MetaModel::GetObject('Server', $iServer);
  4160. $oServer->Set('physicalinterface_list', $oLinkset);
  4161. $oServer->DBWrite();
  4162. // Check Results
  4163. $bFoundIssue = false;
  4164. $oServer = MetaModel::GetObject('Server', $iServer);
  4165. $oLinkset = $oServer->Get('physicalinterface_list');
  4166. $aRes = $this->StandardizedDump($oLinkset, 'zzz');
  4167. $sRes = var_export($aRes, true);
  4168. echo "Found: <pre>".$sRes."</pre>\n";
  4169. $sExpectedRes = var_export($aScenario['expected-res'], true);
  4170. if ($sRes != $sExpectedRes)
  4171. {
  4172. $bFoundIssue = true;
  4173. echo "NOT COMPLIANT!!! Expecting: <pre>".$sExpectedRes."</pre>\n";
  4174. }
  4175. // Check History
  4176. $aQueryParams = array('change' => $iChange, 'objclass' => get_class($oServer), 'objkey' => $oServer->GetKey());
  4177. $oAdded = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'added'"), array(), $aQueryParams);
  4178. echo "added: ".$oAdded->Count()."<br/>\n";
  4179. if ($aScenario['history_added'] != $oAdded->Count())
  4180. {
  4181. $bFoundIssue = true;
  4182. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_added']."<br/>\n";
  4183. }
  4184. $oRemoved = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'removed'"), array(), $aQueryParams);
  4185. echo "removed: ".$oRemoved->Count()."<br/>\n";
  4186. if ($aScenario['history_removed'] != $oRemoved->Count())
  4187. {
  4188. $bFoundIssue = true;
  4189. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_removed']."<br/>\n";
  4190. }
  4191. $oModified = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksTune WHERE objclass = :objclass AND objkey = :objkey AND change = :change"), array(), $aQueryParams);
  4192. echo "modified: ".$oModified->Count()."<br/>\n";
  4193. if ($aScenario['history_modified'] != $oModified->Count())
  4194. {
  4195. $bFoundIssue = true;
  4196. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_modified']."<br/>\n";
  4197. }
  4198. if ($bFoundIssue)
  4199. {
  4200. throw new Exception('Stopping on failed scenario');
  4201. }
  4202. }
  4203. }
  4204. }
  4205. class TestLinkSetRecording_1NAdd_Remove extends TestLinkSet
  4206. {
  4207. static public function GetName()
  4208. {
  4209. return 'Linkset 1-N (Delivery Model vs Organization: Edit Add/Remove)';
  4210. }
  4211. static public function GetDescription()
  4212. {
  4213. return 'Simulate CSV/data synchro type of recording. Check the values and the history.';
  4214. }
  4215. protected function DoExecute()
  4216. {
  4217. CMDBSource::Query('START TRANSACTION');
  4218. //CMDBSource::Query('ROLLBACK'); automatique !
  4219. ////////////////////////////////////////////////////////////////////////////////
  4220. // Set the stage
  4221. //
  4222. $oProvider = new Organization();
  4223. $oProvider->Set('name', 'Test-Provider1');
  4224. $oProvider->DBInsert();
  4225. $iProvider = $oProvider->GetKey();
  4226. $oDM1 = new DeliveryModel();
  4227. $oDM1->Set('name', 'Test-DM-1');
  4228. $oDM1->Set('org_id', $iProvider);
  4229. $oDM1->DBInsert();
  4230. $iDM1 = $oDM1->GetKey();
  4231. $oDM2 = new DeliveryModel();
  4232. $oDM2->Set('name', 'Test-DM-2');
  4233. $oDM2->Set('org_id', $iProvider);
  4234. $oDM2->DBInsert();
  4235. $iDM2 = $oDM2->GetKey();
  4236. ////////////////////////////////////////////////////////////////////////////////
  4237. // Scenarii
  4238. //
  4239. $aScenarii = array(
  4240. array(
  4241. 'description' => 'Add the first customer',
  4242. 'organizations' => array(
  4243. array(
  4244. 'deliverymodel_id' => $iDM1,
  4245. 'name' => 'Test-Customer-1',
  4246. ),
  4247. ),
  4248. 'expected-res' => array (
  4249. "Test-Customer-1, , active, 0, , $iDM1, Test-DM-1, , Test-DM-1",
  4250. ),
  4251. 'history_added' => 0,
  4252. 'history_removed' => 0,
  4253. 'history_modified' => 0,
  4254. ),
  4255. array(
  4256. 'description' => 'Remove the customer by loading an empty set',
  4257. 'organizations' => array(
  4258. ),
  4259. 'expected-res' => array (
  4260. ),
  4261. 'history_added' => 0,
  4262. 'history_removed' => 0,
  4263. 'history_modified' => 0,
  4264. ),
  4265. array(
  4266. 'description' => 'Create two customers at once',
  4267. 'organizations' => array(
  4268. array(
  4269. 'deliverymodel_id' => $iDM1,
  4270. 'name' => 'Test-Customer-1',
  4271. ),
  4272. array(
  4273. 'deliverymodel_id' => $iDM1,
  4274. 'name' => 'Test-Customer-2',
  4275. ),
  4276. ),
  4277. 'expected-res' => array (
  4278. "Test-Customer-1, , active, 0, , $iDM1, Test-DM-1, , Test-DM-1",
  4279. "Test-Customer-2, , active, 0, , $iDM1, Test-DM-1, , Test-DM-1",
  4280. ),
  4281. 'history_added' => 0,
  4282. 'history_removed' => 0,
  4283. 'history_modified' => 0,
  4284. ),
  4285. array(
  4286. 'description' => 'Move Customer-1 to the second Delivery Model',
  4287. 'organizations' => array(
  4288. array(
  4289. 'id' => "SELECT Organization WHERE name='Test-Customer-1'",
  4290. 'deliverymodel_id' => $iDM2,
  4291. 'name' => 'Test-Customer-1',
  4292. ),
  4293. array(
  4294. 'deliverymodel_id' => $iDM1,
  4295. 'name' => 'Test-Customer-2',
  4296. ),
  4297. ),
  4298. 'expected-res' => array (
  4299. "Test-Customer-2, , active, 0, , $iDM1, Test-DM-1, , Test-DM-1",
  4300. ),
  4301. 'history_added' => 0,
  4302. 'history_removed' => 0,
  4303. 'history_modified' => 0,
  4304. ),
  4305. array(
  4306. 'description' => 'Move Customer-1 back to the first Delivery Model and reset Customer-2 (no Delivery Model)',
  4307. 'organizations' => array(
  4308. array(
  4309. 'id' => "SELECT Organization WHERE name='Test-Customer-1'",
  4310. 'deliverymodel_id' => $iDM1,
  4311. 'name' => 'Test-Customer-1',
  4312. ),
  4313. array(
  4314. 'id' => "SELECT Organization WHERE name='Test-Customer-2'",
  4315. 'deliverymodel_id' => 0,
  4316. 'name' => 'Test-Customer-2',
  4317. ),
  4318. ),
  4319. 'expected-res' => array (
  4320. "Test-Customer-1, , active, 0, , $iDM1, Test-DM-1, , Test-DM-1",
  4321. ),
  4322. 'history_added' => 0,
  4323. 'history_removed' => 0,
  4324. 'history_modified' => 0,
  4325. ),
  4326. );
  4327. foreach ($aScenarii as $aScenario)
  4328. {
  4329. echo "<h4>".$aScenario['description']."</h4>\n";
  4330. $oChange = MetaModel::NewObject("CMDBChange");
  4331. $oChange->Set("date", time());
  4332. $oChange->Set("userinfo", CMDBChange::GetCurrentUserName());
  4333. $oChange->Set("origin", 'custom-extension');
  4334. $oChange->DBInsert();
  4335. CMDBObject::SetCurrentChange($oChange);
  4336. $iChange = $oChange->GetKey();
  4337. // Prepare set
  4338. $oLinkset = DBObjectSet::FromScratch('Organization');
  4339. foreach ($aScenario['organizations'] as $aOrgData)
  4340. {
  4341. if (array_key_exists('id', $aOrgData))
  4342. {
  4343. $sOQL = $aOrgData['id'];
  4344. $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
  4345. $oOrg = $oSet->Fetch();
  4346. if (!is_object($oOrg)) throw new Exception('Failed to find the Organization: '.$sOQL);
  4347. }
  4348. else
  4349. {
  4350. $oOrg = MetaModel::NewObject('Organization');
  4351. }
  4352. foreach ($aOrgData as $sAttCode => $value)
  4353. {
  4354. if ($sAttCode == 'id') continue;
  4355. $oOrg->Set($sAttCode, $value);
  4356. }
  4357. $oLinkset->AddObject($oOrg);
  4358. }
  4359. // Write
  4360. $oDM = MetaModel::GetObject('DeliveryModel', $iDM1);
  4361. $oDM->Set('customers_list', $oLinkset);
  4362. $oDM->DBWrite();
  4363. // Check Results
  4364. $bFoundIssue = false;
  4365. $oDM = MetaModel::GetObject('DeliveryModel', $iDM1);
  4366. $oLinkset = $oDM->Get('customers_list');
  4367. $aRes = $this->StandardizedDump($oLinkset, 'zzz');
  4368. $sRes = var_export($aRes, true);
  4369. echo "Found: <pre>".$sRes."</pre>\n";
  4370. $sExpectedRes = var_export($aScenario['expected-res'], true);
  4371. if ($sRes != $sExpectedRes)
  4372. {
  4373. $bFoundIssue = true;
  4374. echo "NOT COMPLIANT!!! Expecting: <pre>".$sExpectedRes."</pre>\n";
  4375. }
  4376. // Check History
  4377. $aQueryParams = array('change' => $iChange, 'objclass' => get_class($oDM), 'objkey' => $oDM->GetKey());
  4378. $oAdded = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'added'"), array(), $aQueryParams);
  4379. echo "added: ".$oAdded->Count()."<br/>\n";
  4380. if ($aScenario['history_added'] != $oAdded->Count())
  4381. {
  4382. $bFoundIssue = true;
  4383. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_added']."<br/>\n";
  4384. }
  4385. $oRemoved = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksAddRemove WHERE objclass = :objclass AND objkey = :objkey AND change = :change AND type = 'removed'"), array(), $aQueryParams);
  4386. echo "removed: ".$oRemoved->Count()."<br/>\n";
  4387. if ($aScenario['history_removed'] != $oRemoved->Count())
  4388. {
  4389. $bFoundIssue = true;
  4390. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_removed']."<br/>\n";
  4391. }
  4392. $oModified = new DBObjectSet(DBSearch::FromOQL("SELECT CMDBChangeOpSetAttributeLinksTune WHERE objclass = :objclass AND objkey = :objkey AND change = :change"), array(), $aQueryParams);
  4393. echo "modified: ".$oModified->Count()."<br/>\n";
  4394. if ($aScenario['history_modified'] != $oModified->Count())
  4395. {
  4396. $bFoundIssue = true;
  4397. echo "NOT COMPLIANT!!! Expecting: ".$aScenario['history_modified']."<br/>\n";
  4398. }
  4399. if ($bFoundIssue)
  4400. {
  4401. throw new Exception('Stopping on failed scenario');
  4402. }
  4403. }
  4404. }
  4405. }
  4406. class TestDateTimeFormats extends TestBizModel
  4407. {
  4408. static public function GetName() {return 'Check Date & Time formating and parsing';}
  4409. static public function GetDescription() {return 'Check the formating and parsing of dates for various formats';}
  4410. public function DoExecute()
  4411. {
  4412. require_once(APPROOT.'core/datetimeformat.class.inc.php');
  4413. $bRet = true;
  4414. $aTestFormats = array(
  4415. 'French (short)' => 'd/m/Y H:i:s',
  4416. 'French (short - no seconds)' => 'd/m/Y H:i',
  4417. 'French (long)' => 'd/m/Y H\\h i\\m\\i\\n s\\s',
  4418. 'English US' => 'm/d/Y H:i:s',
  4419. 'English US (12 hours)' => 'm/d/Y h:i:s a',
  4420. 'English US (12 hours, short)' => 'n/j/Y g:i:s a',
  4421. 'English UK' => 'd/m/Y H:i:s',
  4422. 'German' => 'd.m.Y H:i:s',
  4423. 'SQL' => 'Y-m-d H:i:s',
  4424. );
  4425. // Valid date and times, all tests should pass
  4426. $aTestDates = array('2015-01-01 00:00:00', '2015-12-31 23:59:00', '2016-01-01 08:21:00', '2016-02-28 12:30:00', '2016-02-29 16:47:00', /*'2016-02-29 14:30:17'*/);
  4427. foreach($aTestFormats as $sDesc => $sFormat)
  4428. {
  4429. $this->ReportSuccess("Test of the '$sDesc' format: '$sFormat':");
  4430. $oFormat = new DateTimeFormat($sFormat);
  4431. foreach($aTestDates as $sTestDate)
  4432. {
  4433. $oDate = new DateTime($sTestDate);
  4434. $sFormattedDate = $oFormat->Format($oDate);
  4435. $oParsedDate = $oFormat->Parse($sFormattedDate);
  4436. $sPattern = $oFormat->ToRegExpr('/');
  4437. $bParseOk = ($oParsedDate->format('Y-m-d H:i:s') == $sTestDate);
  4438. if (!$bParseOk)
  4439. {
  4440. $this->ReportError('Parsed ('.$sFormattedDate.') date different from initial date (difference of '.((int)$oParsedDate->format('U')- (int)$oDate->format('U')).'s)');
  4441. $bRet = false;
  4442. }
  4443. $bValidateOk = preg_match($sPattern, $sFormattedDate);
  4444. if (!$bValidateOk)
  4445. {
  4446. $this->ReportError('Formatted date ('.$sFormattedDate.') does not match the validation pattern ('.$sPattern.')');
  4447. $bRet = false;
  4448. }
  4449. $this->ReportSuccess("Formatted date: $sFormattedDate - Parsing: ".($bParseOk ? 'Ok' : '<b>KO</b>')." - Validation: ".($bValidateOk ? 'Ok' : '<b>KO</b>'));
  4450. }
  4451. echo "</p>\n";
  4452. }
  4453. // Invalid date & time strings, all regexpr validation should fail
  4454. $aInvalidTestDates = array(
  4455. 'SQL' => array('2015-13-01 00:00:00', '2015-12-51 23:59:00', '2016-01-01 +08:21:00', '2016-02-28 24:30:00', '2016-02-29 16:67:88'),
  4456. 'French (short)' => array('01/01/20150 00:00:00', '01/01/20150 00:00:00', '01/13/2015 00:00:00', '01/01/2015 40:00:00', '01/01/2015 00:99:00'),
  4457. 'English US (12 hours)' => array('13/01/2015 12:00:00 am', '12/33/2015 12:00:00 am', '12/23/215 12:00:00 am', '05/04/2016 16:00:00 am', '05/04/2016 10:00:00 ap'),
  4458. );
  4459. foreach($aInvalidTestDates as $sFormatName => $aDatesToParse)
  4460. {
  4461. $sFormat = $aTestFormats[$sFormatName];
  4462. $oFormat = new DateTimeFormat($sFormat);
  4463. $this->ReportSuccess("Test of the '$sFormatName' format: '$sFormat':");
  4464. foreach($aDatesToParse as $sDate)
  4465. {
  4466. $sPattern = $oFormat->ToRegExpr('/');
  4467. $bValidateOk = preg_match($sPattern, $sDate);
  4468. if ($bValidateOk)
  4469. {
  4470. $this->ReportError('Formatted date ('.$sFormattedDate.') matches the validation pattern ('.$sPattern.') whereas it should not!');
  4471. $bRet = false;
  4472. }
  4473. $this->ReportSuccess("Formatted date: $sDate - Validation: ".($bValidateOk ? '<b>KO</n>' : 'rejected, Ok.'));
  4474. }
  4475. }
  4476. return $bRet;
  4477. }
  4478. }
  4479. class TestExecActions extends TestBizModel
  4480. {
  4481. static public function GetName()
  4482. {
  4483. return 'Scripted actions API DBObject::ExecAction - syntax errors';
  4484. }
  4485. static public function GetDescription()
  4486. {
  4487. return 'Check that wrong arguments are correclty reported';
  4488. }
  4489. protected function DoExecute()
  4490. {
  4491. $oSource = new UserRequest();
  4492. $oSource->Set('title', 'Houston!');
  4493. $oSource->Set('description', 'Looks like we have a problem');
  4494. $oTarget = new Server();
  4495. ////////////////////////////////////////////////////////////////////////////////
  4496. // Scenarii
  4497. //
  4498. $aScenarii = array(
  4499. array(
  4500. 'action' => 'set',
  4501. 'error' => 'Action: set - Invalid syntax'
  4502. ),
  4503. array(
  4504. 'action' => 'smurf()',
  4505. 'error' => 'Action: smurf() - Invalid verb'
  4506. ),
  4507. array(
  4508. 'action' => ' smurf () ',
  4509. 'error' => 'Action: smurf () - Invalid syntax'
  4510. ),
  4511. array(
  4512. 'action' => 'clone(some_att_code, another_one)',
  4513. 'error' => 'Action: clone(some_att_code, another_one) - Unknown attribute Server::some_att_code'
  4514. ),
  4515. array(
  4516. 'action' => 'copy(toto, titi)',
  4517. 'error' => 'Action: copy(toto, titi) - Unknown attribute Server::titi'
  4518. ),
  4519. array(
  4520. 'action' => 'copy(toto, name)',
  4521. 'error' => 'Action: copy(toto, name) - Unknown attribute UserRequest::toto'
  4522. ),
  4523. array(
  4524. 'action' => 'copy()',
  4525. 'error' => 'Action: copy() - Missing argument #1: source attribute'
  4526. ),
  4527. array(
  4528. 'action' => 'copy(title)',
  4529. 'error' => 'Action: copy(title) - Missing argument #2: target attribute'
  4530. ),
  4531. array(
  4532. 'action' => 'set(toto)',
  4533. 'error' => 'Action: set(toto) - Unknown attribute Server::toto'
  4534. ),
  4535. array(
  4536. 'action' => 'set(toto, something)',
  4537. 'error' => 'Action: set(toto, something) - Unknown attribute Server::toto'
  4538. ),
  4539. array(
  4540. 'action' => 'set()',
  4541. 'error' => 'Action: set() - Missing argument #1: target attribute'
  4542. ),
  4543. array(
  4544. 'action' => 'reset(toto)',
  4545. 'error' => 'Action: reset(toto) - Unknown attribute Server::toto'
  4546. ),
  4547. array(
  4548. 'action' => 'reset()',
  4549. 'error' => 'Action: reset() - Missing argument #1: target attribute'
  4550. ),
  4551. array(
  4552. 'action' => 'nullify(toto)',
  4553. 'error' => 'Action: nullify(toto) - Unknown attribute Server::toto'
  4554. ),
  4555. array(
  4556. 'action' => 'nullify()',
  4557. 'error' => 'Action: nullify() - Missing argument #1: target attribute'
  4558. ),
  4559. array(
  4560. 'action' => 'append(toto, something)',
  4561. 'error' => 'Action: append(toto, something) - Unknown attribute Server::toto'
  4562. ),
  4563. array(
  4564. 'action' => 'append(name)',
  4565. 'error' => 'Action: append(name) - Missing argument #2: value to append'
  4566. ),
  4567. array(
  4568. 'action' => 'append()',
  4569. 'error' => 'Action: append() - Missing argument #1: target attribute'
  4570. ),
  4571. array(
  4572. 'action' => 'add_to_list(toto, titi)',
  4573. 'error' => 'Action: add_to_list(toto, titi) - Unknown attribute UserRequest::toto'
  4574. ),
  4575. array(
  4576. 'action' => 'add_to_list(caller_id, titi)',
  4577. 'error' => 'Action: add_to_list(caller_id, titi) - Unknown attribute Server::titi'
  4578. ),
  4579. array(
  4580. 'action' => 'add_to_list(caller_id)',
  4581. 'error' => 'Action: add_to_list(caller_id) - Missing argument #2: target attribute (link set)'
  4582. ),
  4583. array(
  4584. 'action' => 'add_to_list()',
  4585. 'error' => 'Action: add_to_list() - Missing argument #1: source attribute'
  4586. ),
  4587. array(
  4588. 'action' => 'apply_stimulus(toto)',
  4589. 'error' => 'Action: apply_stimulus(toto) - Unknown stimulus Server::toto'
  4590. ),
  4591. array(
  4592. 'action' => 'apply_stimulus()',
  4593. 'error' => 'Action: apply_stimulus() - Missing argument #1: stimulus'
  4594. ),
  4595. array(
  4596. 'action' => 'call_method(toto)',
  4597. 'error' => 'Action: call_method(toto) - Unknown method Server::toto()'
  4598. ),
  4599. array(
  4600. 'action' => 'call_method()',
  4601. 'error' => 'Action: call_method() - Missing argument #1: method name'
  4602. ),
  4603. );
  4604. foreach ($aScenarii as $aScenario)
  4605. {
  4606. echo "<h4>".htmlentities($aScenario['action'], ENT_QUOTES, 'UTF-8')."</h4>\n";
  4607. $sMessage = '';
  4608. try
  4609. {
  4610. $oTarget->ExecActions(array($aScenario['action']), array('source' => $oSource));
  4611. $sMessage = 'Expecting an exception... none has been thrown!';
  4612. }
  4613. catch (Exception $e)
  4614. {
  4615. if ($e->getMessage() != $aScenario['error'])
  4616. {
  4617. $sMessage = 'Wrong message: expecting "'.$aScenario['error'].'" and got "'.$e->getMessage().'"';
  4618. }
  4619. }
  4620. if ($sMessage !='')
  4621. {
  4622. throw new Exception($sMessage);
  4623. }
  4624. }
  4625. }
  4626. }
  4627. class TestIntersectOptimization extends TestBizModel
  4628. {
  4629. static public function GetName()
  4630. {
  4631. return 'Internal query optimizations (pointing to)';
  4632. }
  4633. static public function GetDescription()
  4634. {
  4635. return 'Clever optimization required for the portal to work fine (expected improvement: query never finishing... to an almost instantaneous query!';
  4636. }
  4637. protected function DoExecute()
  4638. {
  4639. $sBaseQuery = 'SELECT Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"';
  4640. $aQueries = array(
  4641. // Exact same query
  4642. 'SELECT Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "The World Company"',
  4643. // Same query, other aliases
  4644. 'SELECT Service AS s2 JOIN Organization AS o2 ON s2.org_id = o2.id WHERE o2.name = "The World Company"',
  4645. // Same aliases, different condition
  4646. 'SELECT Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.parent_id = 0',
  4647. // Other aliases, different condition
  4648. 'SELECT Service AS s2 JOIN Organization AS o2 ON s2.org_id = o2.id WHERE o2.parent_id = 0',
  4649. // Same aliases, simpler query tree
  4650. 'SELECT Service AS s WHERE name LIKE "Save the World"',
  4651. // Other aliases, simpler query tree
  4652. 'SELECT Service AS s2 WHERE name LIKE "Save the World"',
  4653. // Same aliases, different query tree
  4654. 'SELECT Service AS s JOIN ServiceFamily AS f ON s.servicefamily_id = f.id WHERE s.org_id = 123 AND f.name = "Care"',
  4655. // Other aliases, different query tree
  4656. 'SELECT Service AS s2 JOIN ServiceFamily AS f ON s2.servicefamily_id = f.id WHERE s2.org_id = 123 AND f.name = "Care"',
  4657. );
  4658. echo "<h4>Base query: ".htmlentities($sBaseQuery, ENT_QUOTES, 'UTF-8')."</h4>\n";
  4659. foreach ($aQueries as $sOQL)
  4660. {
  4661. echo "<h5>Checking: ".htmlentities($sOQL, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4662. $oSearchA = DBSearch::FromOQL($sBaseQuery);
  4663. $oSearchB = DBSearch::FromOQL($sOQL);
  4664. $oIntersect = $oSearchA->Intersect($oSearchB);
  4665. echo "<p>Intersect: ".htmlentities($oIntersect->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4666. CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
  4667. echo "<p>Successfully tested the SQL query.</p>\n";
  4668. }
  4669. }
  4670. }
  4671. class TestIntersectOptimization2 extends TestBizModel
  4672. {
  4673. static public function GetName()
  4674. {
  4675. return 'Internal query optimizations (referenced by)';
  4676. }
  4677. static public function GetDescription()
  4678. {
  4679. return 'Clever optimization required for the portal to work fine (expected improvement: query never finishing... to an almost instantaneous query!';
  4680. }
  4681. protected function DoExecute()
  4682. {
  4683. $sBaseQuery = 'SELECT Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"';
  4684. $aQueries = array(
  4685. // Exact same query
  4686. 'SELECT Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.name = "Help"',
  4687. // Same query, other aliases
  4688. 'SELECT Organization AS o2 JOIN Service AS s2 ON s2.org_id = o2.id WHERE s2.name = "Help"',
  4689. // Same aliases, different condition
  4690. 'SELECT Organization AS o JOIN Service AS s ON s.org_id = o.id WHERE s.servicefamily_id = 321',
  4691. // Other aliases, different condition
  4692. 'SELECT Organization AS o2 JOIN Service AS s2 ON s2.org_id = o2.id WHERE s2.servicefamily_id = 321',
  4693. // Same aliases, simpler query tree
  4694. 'SELECT Organization AS o WHERE o.name = "Demo"',
  4695. // Other aliases, simpler query tree
  4696. 'SELECT Organization AS o2 WHERE o2.name = "Demo"',
  4697. // Same aliases, different query tree
  4698. 'SELECT Organization AS o JOIN Location AS l ON l.org_id = o.id WHERE l.name = "Paris"',
  4699. // Other aliases, different query tree
  4700. 'SELECT Organization AS o2 JOIN Location AS l ON l.org_id = o2.id WHERE l.name = "Paris"',
  4701. );
  4702. echo "<h4>Base query: ".htmlentities($sBaseQuery, ENT_QUOTES, 'UTF-8')."</h4>\n";
  4703. foreach ($aQueries as $sOQL)
  4704. {
  4705. echo "<h5>Checking: ".htmlentities($sOQL, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4706. $oSearchA = DBSearch::FromOQL($sBaseQuery);
  4707. $oSearchB = DBSearch::FromOQL($sOQL);
  4708. $oIntersect = $oSearchA->Intersect($oSearchB);
  4709. echo "<p>Intersect: ".htmlentities($oIntersect->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4710. CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
  4711. echo "<p>Successfully tested the SQL query.</p>\n";
  4712. }
  4713. }
  4714. }
  4715. class TestIntersectOptimization3 extends TestBizModel
  4716. {
  4717. static public function GetName()
  4718. {
  4719. return 'Internal query optimizations (mix)';
  4720. }
  4721. static public function GetDescription()
  4722. {
  4723. return 'Clever optimization required for the portal to work fine (expected improvement: query never finishing... to an almost instantaneous query!';
  4724. }
  4725. protected function DoExecute()
  4726. {
  4727. $aQueries = array(
  4728. array(
  4729. 'SELECT Organization AS o',
  4730. 'SELECT Organization AS o JOIN Location AS l ON l.org_id = o.id JOIN Organization AS p ON o.parent_id = p.id WHERE l.name = "Paris" AND p.code LIKE "toto"',
  4731. ),
  4732. array(
  4733. 'SELECT UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "left_name"',
  4734. 'SELECT UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "right_name"',
  4735. ),
  4736. );
  4737. echo "<h4>Mixing....</h4>\n";
  4738. foreach ($aQueries as $aQ)
  4739. {
  4740. $sBaseQuery = $aQ[0];
  4741. $sOQL = $aQ[1];
  4742. echo "<h5>Left: ".htmlentities($sBaseQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4743. echo "<h5>Right: ".htmlentities($sOQL, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4744. $oSearchA = DBSearch::FromOQL($sBaseQuery);
  4745. $oSearchB = DBSearch::FromOQL($sOQL);
  4746. $oIntersect = $oSearchA->Intersect($oSearchB);
  4747. echo "<p>Intersect: ".htmlentities($oIntersect->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4748. CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
  4749. echo "<p>Successfully tested the SQL query.</p>\n";
  4750. }
  4751. }
  4752. }
  4753. class TestIntersectOptimization4 extends TestBizModel
  4754. {
  4755. static public function GetName()
  4756. {
  4757. return 'Internal query optimizations (Folding on Join/ReferencedBy)';
  4758. }
  4759. static public function GetDescription()
  4760. {
  4761. return 'Clever optimization required for the portal to work fine (expected improvement: query never finishing... to an almost instantaneous query!';
  4762. }
  4763. protected function DoExecute()
  4764. {
  4765. echo "<h4>Here we are (conluding a long series of tests)</h4>\n";
  4766. $sQueryA = 'SELECT UserRequest AS r JOIN Service AS s ON r.service_id = s.id JOIN Organization AS o ON s.org_id = o.id WHERE r.agent_id = 456 AND s.servicefamily_id = 789 AND o.name = "right_name"';
  4767. $sQueryB = 'SELECT Service AS s JOIN Organization AS o ON s.org_id = o.id WHERE o.name = "some name"';
  4768. echo "<h5>A: ".htmlentities($sQueryA, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4769. echo "<h5>B: ".htmlentities($sQueryB, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4770. $oSearchA = DBSearch::FromOQL($sQueryA);
  4771. $oSearchB = DBSearch::FromOQL($sQueryB);
  4772. $oSearchB->AddCondition_ReferencedBy($oSearchA, 'service_id');
  4773. echo "<p>Referenced by...: ".htmlentities($oSearchB->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4774. CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
  4775. echo "<p>Successfully tested the SQL query.</p>\n";
  4776. }
  4777. }
  4778. class TestIntersectOptimization5 extends TestBizModel
  4779. {
  4780. static public function GetName()
  4781. {
  4782. return 'Internal query optimizations (Folding on Join/PointingTo)';
  4783. }
  4784. static public function GetDescription()
  4785. {
  4786. return 'Clever optimization required for the portal to work fine (expected improvement: query never finishing... to an almost instantaneous query!';
  4787. }
  4788. protected function DoExecute()
  4789. {
  4790. echo "<h4>Here we are (concluding a long series of tests)</h4>\n";
  4791. $sQueryA = 'SELECT Organization AS o JOIN UserRequest AS r ON r.org_id = o.id JOIN Person AS p ON r.caller_id = p.id WHERE o.name LIKE "Company" AND r.service_id = 123 AND p.employee_number LIKE "007"';
  4792. $sQueryB = 'SELECT UserRequest AS ur JOIN Person AS p ON ur.agent_id = p.id WHERE p.status != "terminated"';
  4793. echo "<h5>A: ".htmlentities($sQueryA, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4794. echo "<h5>B: ".htmlentities($sQueryB, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4795. $oSearchA = DBSearch::FromOQL($sQueryA);
  4796. $oSearchB = DBSearch::FromOQL($sQueryB);
  4797. $oSearchB->AddCondition_PointingTo($oSearchA, 'org_id');
  4798. echo "<p>Pointing to...: ".htmlentities($oSearchB->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4799. CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
  4800. echo "<p>Successfully tested the SQL query.</p>\n";
  4801. }
  4802. }
  4803. class TestParsingOptimization extends TestBizModel
  4804. {
  4805. static public function GetName()
  4806. {
  4807. return 'Query optimizations (Merging joins on OQL parsing)';
  4808. }
  4809. static public function GetDescription()
  4810. {
  4811. return 'Checking a few queries that do involve query optimizations (implemented for the sake of optimizing the portal)';
  4812. }
  4813. protected function DoExecute()
  4814. {
  4815. $aQueries = array(
  4816. "SELECT UserRequest AS u
  4817. JOIN Person AS p1 ON u.caller_id=p1.id
  4818. JOIN Organization AS o1 ON p1.org_id=o1.id
  4819. JOIN Person AS p2 ON u.caller_id=p2.id WHERE p2.status='active' AND p1.status='inactive'",
  4820. "SELECT UserRequest AS u
  4821. JOIN Person AS p1 ON u.caller_id=p1.id
  4822. JOIN Person AS p2 ON u.caller_id=p2.id WHERE p2.status='active' AND p1.status='inactive'",
  4823. "SELECT UserRequest AS u
  4824. JOIN Person AS p1 ON u.caller_id=p1.id
  4825. JOIN Organization AS o1 ON p1.org_id=o1.id
  4826. JOIN Person ON u.caller_id=Person.id
  4827. JOIN Location AS l ON Person.location_id = l.id WHERE Person.status='active' AND p1.status='inactive' AND l.country='France'",
  4828. );
  4829. foreach ($aQueries as $sQuery)
  4830. {
  4831. echo "<h5>To Parse: ".htmlentities($sQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4832. $oSearch = DBSearch::FromOQL($sQuery);
  4833. $sQueryOpt = $oSearch->ToOQL();
  4834. echo "<h5>Optimized: ".htmlentities($sQueryOpt, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4835. CMDBSource::TestQuery($oSearch->MakeSelectQuery());
  4836. echo "<p>Successfully tested the SQL query.</p>\n";
  4837. }
  4838. }
  4839. }
  4840. class TestUnions extends TestBizModel
  4841. {
  4842. static public function GetName()
  4843. {
  4844. return 'Unions';
  4845. }
  4846. static public function GetDescription()
  4847. {
  4848. return 'Checking a few UNION queries';
  4849. }
  4850. protected function DoExecute()
  4851. {
  4852. // The two first items did reveal an issue with the query cache,
  4853. //because SELECT Person on the second line must not give the same query as SELECT Person on the first line
  4854. $aQueries = array(
  4855. "SELECT Person UNION SELECT Person" => true,
  4856. "SELECT Person UNION SELECT Team" => true,
  4857. "SELECT Person UNION SELECT Contact" => true,
  4858. "SELECT Contact UNION SELECT Person" => true,
  4859. "SELECT Person UNION SELECT Organization" => false,
  4860. );
  4861. foreach ($aQueries as $sQuery => $bSuccess)
  4862. {
  4863. echo "<h5>To Parse: ".htmlentities($sQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4864. try
  4865. {
  4866. $oSearch = DBSearch::FromOQL($sQuery);
  4867. if (!$bSuccess) throw new Exception('This query should not be parsable!');
  4868. CMDBSource::TestQuery($oSearch->MakeSelectQuery());
  4869. echo "<p>Successfully tested the SQL query.</p>\n";
  4870. }
  4871. catch (OQLException $e)
  4872. {
  4873. if ($bSuccess) throw $e;
  4874. echo "<p>Failed as expected.</p>\n";
  4875. }
  4876. }
  4877. }
  4878. }
  4879. class TestImplicitAlias extends TestBizModel
  4880. {
  4881. static public function GetName()
  4882. {
  4883. return 'OQLImplicitAliases';
  4884. }
  4885. static public function GetDescription()
  4886. {
  4887. return 'Checking implicit aliases resolution';
  4888. }
  4889. protected function DoExecute()
  4890. {
  4891. // The two first items did reveal an issue with the query cache,
  4892. //because SELECT Person on the second line must not give the same query as SELECT Person on the first line
  4893. $aQueries = array(
  4894. "SELECT Person WHERE org_id = 1" => true,
  4895. "SELECT Person WHERE s.org_id = 1" => false,
  4896. "SELECT Person AS p WHERE p.org_id = 1" => true,
  4897. "SELECT Person AS p WHERE Person.org_id = 1" => false,
  4898. "SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE org_id = 2" => true, // Bug N.539
  4899. "SELECT Server JOIN Location ON Server.location_id = Location.id" => true,
  4900. "SELECT Server JOIN Location ON Server.location_id = id" => false,
  4901. "SELECT Server JOIN Location ON Server = Location.id" => false,
  4902. "SELECT Server JOIN Location ON Server.location_id = Location.id WHERE Server.org_id = 1" => true,
  4903. "SELECT Server JOIN Location ON Server.location_id = Location.id WHERE org_id = 1" => false,
  4904. );
  4905. foreach ($aQueries as $sQuery => $bSuccess)
  4906. {
  4907. echo "<h5>To Parse: ".htmlentities($sQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4908. try
  4909. {
  4910. $oSearch = DBSearch::FromOQL($sQuery);
  4911. if (!$bSuccess) throw new Exception('This query should not be parsable!');
  4912. CMDBSource::TestQuery($oSearch->MakeSelectQuery());
  4913. echo "<p>Successfully tested the SQL query.</p>\n";
  4914. }
  4915. catch (OQLException $e)
  4916. {
  4917. if ($bSuccess) throw $e;
  4918. echo "<p>Failed as expected.</p>\n";
  4919. }
  4920. }
  4921. }
  4922. }
  4923. class TestIntersectNotOptimized extends TestBizModel
  4924. {
  4925. static public function GetName()
  4926. {
  4927. return 'Internal query NOT optimized';
  4928. }
  4929. static public function GetDescription()
  4930. {
  4931. return '(N.718) Sometimes, the optimization CANNOT be performed because merging two different classes (same branch) is not implemented';
  4932. }
  4933. protected function DoExecute()
  4934. {
  4935. echo "<h4>Intersect NOT optimized on 'pointing to'</h4>\n";
  4936. $sBaseQuery = 'SELECT lnkContactToFunctionalCI AS l JOIN Contact AS c ON l.contact_id = c.id';
  4937. $sOQL = 'SELECT lnkContactToFunctionalCI AS l JOIN Person AS p ON l.contact_id = p.id';
  4938. echo "<h5>Left: ".htmlentities($sBaseQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4939. echo "<h5>Right: ".htmlentities($sOQL, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4940. $oSearchA = DBSearch::FromOQL($sBaseQuery);
  4941. $oSearchB = DBSearch::FromOQL($sOQL);
  4942. $oIntersect = $oSearchA->Intersect($oSearchB);
  4943. echo "<p>Intersect: ".htmlentities($oIntersect->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4944. CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
  4945. echo "<p>Successfully tested the SQL query.</p>\n";
  4946. echo "<h4>Intersect NOT optimized on 'referenced by'</h4>\n";
  4947. $sBaseQuery = 'SELECT Organization AS o JOIN Contact AS c ON c.org_id = o.id WHERE c.id = 1';
  4948. $sOQL = 'SELECT Organization AS o JOIN Person AS p ON p.org_id = o.id WHERE p.id = 2';
  4949. echo "<h5>Left: ".htmlentities($sBaseQuery, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4950. echo "<h5>Right: ".htmlentities($sOQL, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4951. $oSearchA = DBSearch::FromOQL($sBaseQuery);
  4952. $oSearchB = DBSearch::FromOQL($sOQL);
  4953. $oIntersect = $oSearchA->Intersect($oSearchB);
  4954. echo "<p>Intersect: ".htmlentities($oIntersect->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4955. CMDBSource::TestQuery($oIntersect->MakeSelectQuery());
  4956. echo "<p>Successfully tested the SQL query.</p>\n";
  4957. echo "<h4>NOT Folding on AddCondition_PointingTo</h4>\n";
  4958. $sQueryA = 'SELECT Organization AS o JOIN Contact AS c ON c.org_id = o.id';
  4959. $sQueryB = 'SELECT Person';
  4960. echo "<h5>A: ".htmlentities($sQueryA, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4961. echo "<h5>B: ".htmlentities($sQueryB, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4962. $oSearchA = DBSearch::FromOQL($sQueryA);
  4963. $oSearchB = DBSearch::FromOQL($sQueryB);
  4964. $oSearchB->AddCondition_PointingTo($oSearchA, 'org_id');
  4965. echo "<p>Pointing to...: ".htmlentities($oSearchB->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4966. CMDBSource::TestQuery($oSearchB->MakeSelectQuery());
  4967. echo "<p>Successfully tested the SQL query.</p>\n";
  4968. echo "<h4>NOT Folding on AddCondition_ReferencedBy</h4>\n";
  4969. $sQueryA = 'SELECT lnkContactToFunctionalCI AS l JOIN Contact AS c ON l.contact_id = c.id';
  4970. $sQueryB = 'SELECT Person';
  4971. echo "<h5>A: ".htmlentities($sQueryA, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4972. echo "<h5>B: ".htmlentities($sQueryB, ENT_QUOTES, 'UTF-8')."</h5>\n";
  4973. $oSearchA = DBSearch::FromOQL($sQueryA);
  4974. $oSearchB = DBSearch::FromOQL($sQueryB);
  4975. $oSearchB->AddCondition_ReferencedBy($oSearchA, 'contact_id');
  4976. echo "<p>Referenced by...: ".htmlentities($oSearchA->ToOQL(), ENT_QUOTES, 'UTF-8')."</p>\n";
  4977. CMDBSource::TestQuery($oSearchA->MakeSelectQuery());
  4978. echo "<p>Successfully tested the SQL query.</p>\n";
  4979. }
  4980. }
  4981. class TestBug609 extends TestBizModel
  4982. {
  4983. static public function GetName()
  4984. {
  4985. return 'UNION with JOINS ordered differently';
  4986. }
  4987. static public function GetDescription()
  4988. {
  4989. return '(N.609) Inconsistent SQL query (various symptoms, must mostly in the form of "Class \'IT Department\' not found"';
  4990. }
  4991. protected function DoExecute()
  4992. {
  4993. $sQueryA = 'SELECT t,o FROM Team AS t JOIN Organization AS o ON t.org_id = o.id';
  4994. $sQueryB = 'SELECT t,o FROM Organization AS o JOIN Team AS t ON t.org_id = o.id';
  4995. $oSearch = DBSearch::FromOQL("$sQueryB UNION $sQueryA");
  4996. $oSet = new DBObjectSet($oSearch);
  4997. while($oObject = $oSet->Fetch())
  4998. {
  4999. echo "Successfull load for <b>".$oObject->GetName()."</b><br>\n";
  5000. }
  5001. }
  5002. }
  5003. class TestBug788 extends TestBizModel
  5004. {
  5005. static public function GetName()
  5006. {
  5007. return 'Graph - delete nodes';
  5008. }
  5009. static public function GetDescription()
  5010. {
  5011. return '(N.788) Graph not refreshed when unchecking some classes';
  5012. }
  5013. protected function DoExecute()
  5014. {
  5015. $oGraph = new SimpleGraph();
  5016. $a = new GraphNode($oGraph, 'A');
  5017. $b = new GraphNode($oGraph, 'B');
  5018. $c = new GraphNode($oGraph, 'C');
  5019. new GraphEdge($oGraph, 'A--B', $a, $b);
  5020. new GraphEdge($oGraph, 'B--C', $b, $c);
  5021. new GraphEdge($oGraph, 'C--B', $c, $b);
  5022. echo "<h5>Graphe initial</h5>";
  5023. echo $oGraph->DumpAsHtmlImage();
  5024. echo $oGraph->DumpAsHTMLText();
  5025. echo "<h5>Removing C</h5>";
  5026. $oGraph->FilterNode($c);
  5027. unset($c);
  5028. echo $oGraph->DumpAsHtmlImage();
  5029. echo $oGraph->DumpAsHTMLText();
  5030. if ((count($oGraph->_GetNodes()) != 2) || (count($oGraph->_GetEdges()) != 1))
  5031. {
  5032. throw new Exception('The graph should be made of 2 nodes and 1 edge');
  5033. }
  5034. echo "<h5>Removing B</h5>";
  5035. $oGraph->FilterNode($b);
  5036. unset($b);
  5037. echo $oGraph->DumpAsHtmlImage();
  5038. echo $oGraph->DumpAsHTMLText();
  5039. if ((count($oGraph->_GetNodes()) != 1) || (count($oGraph->_GetEdges()) != 0))
  5040. {
  5041. throw new Exception('The graph should contain only the node A');
  5042. }
  5043. }
  5044. }
  5045. class WhereIsThe61TablesThreat extends TestBizModel
  5046. {
  5047. static public function GetName()
  5048. {
  5049. return '61 tables';
  5050. }
  5051. static public function GetDescription()
  5052. {
  5053. return 'Evaluate where is the 61 tables limit threat';
  5054. }
  5055. protected function DoExecute()
  5056. {
  5057. $aClassToCount_Full = array();
  5058. $aDistribution = array();
  5059. $iTotalClasses = 0;
  5060. foreach (MetaModel::GetClasses() as $sClass)
  5061. {
  5062. if (MetaModel::IsAbstract($sClass)) continue;
  5063. $iTotalClasses++;
  5064. $oSearch = DBSearch::FromOQL("SELECT $sClass WHERE id = 1");
  5065. $oSql = $oSearch->GetSQLQueryStructure(array(), false, null);
  5066. $iCount = $oSql->CountTables();
  5067. $aClassToCount_Full[$sClass] = $iCount;
  5068. if (array_key_exists($iCount, $aDistribution))
  5069. {
  5070. $aDistribution[$iCount]++;
  5071. }
  5072. else
  5073. {
  5074. $aDistribution[$iCount] = 1;
  5075. }
  5076. }
  5077. arsort($aClassToCount_Full);
  5078. $iHighestCount = max($aClassToCount_Full);
  5079. for($i = 1; $i < $iHighestCount ; $i++)
  5080. {
  5081. if (!array_key_exists($i, $aDistribution))
  5082. {
  5083. $aDistribution[$i] = 0;
  5084. }
  5085. }
  5086. ksort($aDistribution);
  5087. $i = 0;
  5088. $iLimit = 15;
  5089. $iCountThreshold = 10;
  5090. echo "<h5>TOP $iLimit offenders (+ those exceeding $iCountThreshold tables)</h5>";
  5091. foreach ($aClassToCount_Full as $sClass => $iCountFull)
  5092. {
  5093. $i++;
  5094. if (($iCountFull <= $iCountThreshold) && ($i >= $iLimit)) break;
  5095. echo "$sClass: $iCountFull tables<br/>";
  5096. }
  5097. echo "<h5>Distribution of table counts</h5>";
  5098. echo "<p>Over a total of $iTotalClasses instantiable classes.</p>";
  5099. echo "<table>";
  5100. echo "<tr><td>Table count</td><td>Classes</td></tr>";
  5101. foreach ($aDistribution as $iTableCount => $iClassCount)
  5102. {
  5103. echo "<tr><td>$iTableCount</td><td>$iClassCount</td></tr>";
  5104. }
  5105. echo "</table>";
  5106. }
  5107. }
  5108. class TestBug689 extends TestBizModel
  5109. {
  5110. static public function GetName()
  5111. {
  5112. return 'An OQL failing to export in XML';
  5113. }
  5114. static public function GetDescription()
  5115. {
  5116. return '(N.689) Reaching the limit of 61 tables';
  5117. }
  5118. protected function DoExecute()
  5119. {
  5120. $sOql = 'SELECT child, parent, s1, p, o FROM UserRequest AS child JOIN UserRequest AS parent ON child.parent_request_id = parent.id JOIN lnkFunctionalCIToTicket AS l1 ON l1.ticket_id = child.id JOIN Server AS s1 ON l1.functionalci_id = s1.id JOIN Person AS p ON child.caller_id = p.id JOIN Organization AS o ON p.org_id = o.id';
  5121. $oSearch = DBSearch::FromOQL($sOql);
  5122. $oSql = $oSearch->GetSQLQueryStructure(array(), false, null);
  5123. //$sSql = $oSql->RenderSelect();
  5124. echo '<p>'.$sOql.'</p>';
  5125. echo '<p>This query rendered with all columns give a MySQL query having <b>'.$oSql->CountTables().'</b> tables... let\'s try it with the DBObjectSet API:</p>';
  5126. $oSet = new DBObjectSet($oSearch);
  5127. $oObj = $oSet->Fetch();
  5128. echo '<p>Well done, this is working fine! Some magic happened in the background!</p>';
  5129. }
  5130. }
  5131. class TestDBObjectLinkedObjects extends TestBizModel
  5132. {
  5133. static public function GetName()
  5134. {
  5135. return 'DBObject Linked objects API';
  5136. }
  5137. static public function GetDescription()
  5138. {
  5139. return 'Add/Remove/Modify linked objects (recorded as a delta within DBObject, later recorded in DB)';
  5140. }
  5141. protected function DoExecute()
  5142. {
  5143. CMDBSource::Query('START TRANSACTION');
  5144. //CMDBSource::Query('ROLLBACK'); automatique !
  5145. ////////////////////////////////////////////////////////////////////////////////
  5146. // Set the stage
  5147. //
  5148. $oTypes = new DBObjectSet(DBObjectSearch::FromOQL('SELECT NetworkDeviceType WHERE name = "Router"'));
  5149. $oType = $oTypes->fetch();
  5150. $oDevice1 = MetaModel::NewObject('NetworkDevice');
  5151. $oDevice1->Set('name', 'test device 1');
  5152. $oDevice1->Set('org_id', 3);
  5153. $oDevice1->Set('networkdevicetype_id', $oType->GetKey());
  5154. $oDevice1->DBInsert();
  5155. $iDev1 = $oDevice1->GetKey();
  5156. $oDevice2 = MetaModel::NewObject('NetworkDevice');
  5157. $oDevice2->Set('name', 'test device 2');
  5158. $oDevice2->Set('org_id', 3);
  5159. $oDevice2->Set('networkdevicetype_id', $oType->GetKey());
  5160. $oDevice2->DBInsert();
  5161. $iDev2 = $oDevice2->GetKey();
  5162. $oServer = MetaModel::NewObject('Server');
  5163. $oServer->Set('name', 'unit test linkset');
  5164. $oServer->Set('org_id', 3);
  5165. $oLinkSet = $oServer->Get('networkdevice_list');
  5166. $oLinkSet->AddItem(MetaModel::NewObject('lnkConnectableCIToNetworkDevice', array('networkdevice_id' => $iDev1)));
  5167. $oServer->Set('networkdevice_list', $oLinkSet);
  5168. assert($oServer->IsModified(), 'Server is modified');
  5169. $oServer->DBInsert();
  5170. $iServer = $oServer->GetKey();
  5171. $oServer = MetaModel::GetObject('Server', $iServer);
  5172. $oLinkSet = $oServer->Get('networkdevice_list');
  5173. assert($oLinkSet->Count() == 1, 'One NW Dev attached');
  5174. $oLink = $oLinkSet->Fetch();
  5175. assert($oLink->Get('networkdevice_id') == $iDev1, 'New device correctly attached');
  5176. $oLinkSet = $oServer->Get('networkdevice_list');
  5177. $oLinkSet->AddItem(MetaModel::NewObject('lnkConnectableCIToNetworkDevice', array('networkdevice_id' => $iDev2)));
  5178. $oServer->Set('networkdevice_list', $oLinkSet);
  5179. assert($oServer->IsModified(), 'Server is modified');
  5180. $oServer->DBUpdate();
  5181. $oServer = MetaModel::GetObject('Server', $iServer);
  5182. $oLinkSet = $oServer->Get('networkdevice_list');
  5183. assert($oLinkSet->Count() == 2, 'Two NW Dev attached');
  5184. $oNewLinkSet = clone $oLinkSet;
  5185. while ($oLink = $oLinkSet->Fetch())
  5186. {
  5187. $iLinkId = $oLink->Get('networkdevice_id');
  5188. if ($iLinkId == $iDev1)
  5189. {
  5190. $oNewLinkSet->RemoveItem($oLink->GetKey());
  5191. }
  5192. elseif ($iLinkId == $iDev2)
  5193. {
  5194. $oLink->Set('network_port', 'lePortSalut');
  5195. $oNewLinkSet->ModifyItem($oLink);
  5196. }
  5197. }
  5198. $oServer->Set('networkdevice_list', $oNewLinkSet);
  5199. assert($oServer->IsModified(), 'Server is modified');
  5200. $oServer->DBUpdate();
  5201. $oServer = MetaModel::GetObject('Server', $iServer);
  5202. $oLinkSet = $oServer->Get('networkdevice_list');
  5203. assert($oLinkSet->Count() == 1, 'One NW Dev attached');
  5204. $oLink = $oLinkSet->Fetch();
  5205. assert($oLink->Get('networkdevice_id') == $iDev2, 'Dev2 remained attached');
  5206. assert($oLink->Get('network_port') == 'lePortSalut', 'Port has been changed');
  5207. }
  5208. }
  5209. class TestDBObjectLinkedObjectsLegacy extends TestBizModel
  5210. {
  5211. static public function GetName()
  5212. {
  5213. return 'DBObject Linked objects API (legacy usage)';
  5214. }
  5215. static public function GetDescription()
  5216. {
  5217. return 'Alter a link set by redefining the whole list of links (not recommended!)';
  5218. }
  5219. protected function DoExecute()
  5220. {
  5221. CMDBSource::Query('START TRANSACTION');
  5222. //CMDBSource::Query('ROLLBACK'); automatique !
  5223. ////////////////////////////////////////////////////////////////////////////////
  5224. // Set the stage
  5225. //
  5226. $oTypes = new DBObjectSet(DBObjectSearch::FromOQL('SELECT NetworkDeviceType WHERE name = "Router"'));
  5227. $oType = $oTypes->fetch();
  5228. $oDevice1 = MetaModel::NewObject('NetworkDevice');
  5229. $oDevice1->Set('name', 'test device 1');
  5230. $oDevice1->Set('org_id', 3);
  5231. $oDevice1->Set('networkdevicetype_id', $oType->GetKey());
  5232. $oDevice1->DBInsert();
  5233. $iDev1 = $oDevice1->GetKey();
  5234. $oDevice2 = MetaModel::NewObject('NetworkDevice');
  5235. $oDevice2->Set('name', 'test device 2');
  5236. $oDevice2->Set('org_id', 3);
  5237. $oDevice2->Set('networkdevicetype_id', $oType->GetKey());
  5238. $oDevice2->DBInsert();
  5239. $iDev2 = $oDevice2->GetKey();
  5240. $oServer = MetaModel::NewObject('Server');
  5241. $oServer->Set('name', 'unit test linkset');
  5242. $oServer->Set('org_id', 3);
  5243. $oLinkSet = $oServer->Get('networkdevice_list');
  5244. $oNewLinkSet = DBObjectSet::FromScratch('lnkConnectableCIToNetworkDevice');
  5245. while ($oLink = $oLinkSet->Fetch())
  5246. {
  5247. $oNewLinkSet->AddObject($oLink);
  5248. }
  5249. $oNewLinkSet->AddObject(MetaModel::NewObject('lnkConnectableCIToNetworkDevice', array('networkdevice_id' => $iDev1)));
  5250. $oServer->Set('networkdevice_list', $oNewLinkSet);
  5251. assert($oServer->IsModified(), 'Server is modified');
  5252. $oServer->DBInsert();
  5253. $iServer = $oServer->GetKey();
  5254. $oServer = MetaModel::GetObject('Server', $iServer);
  5255. $oLinkSet = $oServer->Get('networkdevice_list');
  5256. assert($oLinkSet->Count() == 1, 'One NW Dev attached');
  5257. $oLink = $oLinkSet->Fetch();
  5258. assert($oLink->Get('networkdevice_id') == $iDev1, 'New device correctly attached');
  5259. $oNewLinkSet = DBObjectSet::FromScratch('lnkConnectableCIToNetworkDevice');
  5260. $oLinkSet->Rewind();
  5261. while ($oLink = $oLinkSet->Fetch())
  5262. {
  5263. $oNewLinkSet->AddObject($oLink);
  5264. }
  5265. $oNewLinkSet->AddObject(MetaModel::NewObject('lnkConnectableCIToNetworkDevice', array('networkdevice_id' => $iDev2)));
  5266. $oServer->Set('networkdevice_list', $oNewLinkSet);
  5267. assert($oServer->IsModified(), 'Server is modified');
  5268. $oServer->DBUpdate();
  5269. $oServer = MetaModel::GetObject('Server', $iServer);
  5270. $oLinkSet = $oServer->Get('networkdevice_list');
  5271. assert($oLinkSet->Count() == 2, 'Two NW Dev attached');
  5272. $oNewLinkSet = DBObjectSet::FromScratch('lnkConnectableCIToNetworkDevice');
  5273. $oServer->Set('networkdevice_list', $oNewLinkSet);
  5274. while ($oLink = $oLinkSet->Fetch())
  5275. {
  5276. $iLinkId = $oLink->Get('networkdevice_id');
  5277. if ($iLinkId == $iDev1)
  5278. {
  5279. // Remove...ie do not add it!
  5280. }
  5281. elseif ($iLinkId == $iDev2)
  5282. {
  5283. $oLink->Set('network_port', 'lePortSalut');
  5284. $oNewLinkSet->AddObject($oLink);
  5285. }
  5286. else
  5287. {
  5288. $oNewLinkSet->AddObject($oLink);
  5289. }
  5290. }
  5291. $oServer->Set('networkdevice_list', $oNewLinkSet);
  5292. assert($oServer->IsModified(), 'Server is modified');
  5293. $oServer->DBUpdate();
  5294. $oServer = MetaModel::GetObject('Server', $iServer);
  5295. $oLinkSet = $oServer->Get('networkdevice_list');
  5296. assert($oLinkSet->Count() == 1, 'One NW Dev attached');
  5297. $oLink = $oLinkSet->Fetch();
  5298. assert($oLink->Get('networkdevice_id') == $iDev2, 'Dev2 remained attached');
  5299. assert($oLink->Get('network_port') == 'lePortSalut', 'Port has been changed');
  5300. }
  5301. }