testlist.inc.php 109 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411
  1. <?php
  2. // Copyright (C) 2010-2012 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-2012 Combodo SARL
  22. * @license http://opensource.org/licenses/AGPL-3.0
  23. */
  24. class TestSQLQuery extends TestScenarioOnDB
  25. {
  26. static public function GetName() {return 'SQLQuery';}
  27. 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';}
  28. static public function GetDBHost() {return 'localhost';}
  29. static public function GetDBUser() {return 'root';}
  30. static public function GetDBPwd() {return '';}
  31. static public function GetDBName() {return 'TestSQLQuery';}
  32. static public function GetDBSubName() {return 'taratata';}
  33. protected function DoPrepare()
  34. {
  35. parent::DoPrepare();
  36. cmdbSource::CreateTable('CREATE TABLE `myTable` (myKey INT(11) NOT NULL auto_increment, column1 VARCHAR(255), column2 VARCHAR(255), PRIMARY KEY (`myKey`)) ENGINE = '.MYSQL_ENGINE);
  37. 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);
  38. 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);
  39. }
  40. protected function DoExecute()
  41. {
  42. $oQuery = new SQLQuery(
  43. $sTable = 'myTable',
  44. $sTableAlias = 'myTableAlias',
  45. $aFields = array('column1'=>new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')),
  46. // $aFullTextNeedles = array('column1'),
  47. $bToDelete = false,
  48. $aValues = array()
  49. );
  50. $oQuery->AddCondition(Expression::FromOQL('DATE(NOW() - 1200 * 2) > \'2008-07-31\''));
  51. $oSubQuery1 = new SQLQuery(
  52. $sTable = 'myTable1',
  53. $sTableAlias = 'myTable1Alias',
  54. $aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')),
  55. // $aFullTextNeedles = array(),
  56. $bToDelete = false,
  57. $aValues = array()
  58. );
  59. $oSubQuery2 = new SQLQuery(
  60. $sTable = 'myTable2',
  61. $sTableAlias = 'myTable2Alias',
  62. $aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')),
  63. // $aFullTextNeedles = array(),
  64. $bToDelete = false,
  65. $aValues = array()
  66. );
  67. $oQuery->AddInnerJoin($oSubQuery1, 'column1', 'column1_1');
  68. $oQuery->AddLeftJoin($oSubQuery2, 'column2', 'column2_2');
  69. $oQuery->DisplayHtml();
  70. $oQuery->RenderDelete();
  71. $oQuery->RenderUpdate();
  72. echo '<p>'.$oQuery->RenderSelect().'</p>';
  73. $oQuery->RenderSelect(array('column1'));
  74. $oQuery->RenderSelect(array('column1', 'column2'));
  75. }
  76. }
  77. class TestOQLParser extends TestFunction
  78. {
  79. static public function GetName() {return 'Check OQL parsing';}
  80. static public function GetDescription() {return 'Attempts a series of queries, and in particular those with a bad syntax';}
  81. protected function CheckQuery($sQuery, $bIsCorrectQuery)
  82. {
  83. $oOql = new OqlInterpreter($sQuery);
  84. try
  85. {
  86. $oTrash = $oOql->Parse(); // Not expecting a given format, otherwise use ParseExpression/ParseObjectQuery/ParseValueSetQuery
  87. self::DumpVariable($oTrash);
  88. }
  89. catch (OQLException $OqlException)
  90. {
  91. if ($bIsCorrectQuery)
  92. {
  93. echo "<p>More info on this unexpected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  94. throw $OqlException;
  95. return false;
  96. }
  97. else
  98. {
  99. // Everything is fine :-)
  100. echo "<p>More info on this expected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
  101. return true;
  102. }
  103. }
  104. // The query was correctly parsed, was it expected to be correct ?
  105. if ($bIsCorrectQuery)
  106. {
  107. return true;
  108. }
  109. else
  110. {
  111. throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
  112. return false;
  113. }
  114. }
  115. protected function TestQuery($sQuery, $bIsCorrectQuery)
  116. {
  117. if (!$this->CheckQuery($sQuery, $bIsCorrectQuery))
  118. {
  119. return false;
  120. }
  121. return true;
  122. }
  123. public function DoExecute()
  124. {
  125. $aQueries = array(
  126. 'SELECT toto' => true,
  127. 'SELECT toto WHERE toto.a = 1' => true,
  128. 'SELECT toto WHERE toto.a = 0xC' => true,
  129. 'SELECT toto WHERE toto.a = \'AXDVFS0xCZ32\'' => true,
  130. 'SELECT toto WHERE toto.a = :myparameter' => true,
  131. 'SELECT toto WHERE toto.a IN (:param1)' => true,
  132. 'SELECT toto WHERE toto.a IN (:param1, :param2)' => true,
  133. 'SELECT toto WHERE toto.a=1' => true,
  134. 'SELECT toto WHERE toto.a = "1"' => true,
  135. 'SELECT toto WHHHERE toto.a = "1"' => false,
  136. 'SELECT toto WHERE toto.a == "1"' => false,
  137. 'SELECT toto WHERE toto.a % 1' => false,
  138. //'SELECT toto WHERE toto.a LIKE 1' => false,
  139. 'SELECT toto WHERE toto.a like \'arg\'' => false,
  140. 'SELECT toto WHERE toto.a NOT LIKE "That\'s it"' => true,
  141. 'SELECT toto WHERE toto.a NOT LIKE "That\'s "it""' => false,
  142. 'SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""' => true,
  143. 'SELECT toto WHERE toto.a NOT LIKE \'That"s it\'' => true,
  144. 'SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'' => false,
  145. 'SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\'' => true,
  146. 'SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"' => false,
  147. 'SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"' => true,
  148. 'SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'' => false,
  149. 'SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\'' => true,
  150. 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
  151. 'SELECT toto WHERE toto.a NOT LIKE "\\""' => true,
  152. 'SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"' => true,
  153. 'SELECT toto WHERE toto.a NOT LIKE "\\\\\\""' => true,
  154. 'SELECT toto WHERE toto.a NOT LIKE ""' => true,
  155. 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
  156. "SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = 'lnkContactRealObject' AND UserRightsMatrixClassGrant.action = 'modify' AND UserRightsMatrixClassGrant.login = 'Denis'" => true,
  157. "SELECT A WHERE A.col1 = 'lit1' AND A.col2 = 'lit2' AND A.col3 = 'lit3'" => true,
  158. 'SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"' => true,
  159. //'SELECT toto WHERE toto.a > \'asd\'' => false,
  160. 'SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345' => true,
  161. 'SELECT Device JOIN Site ON Device.site = Site.id' => true,
  162. 'SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true,
  163. "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,
  164. "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,
  165. "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2" => true,
  166. "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2" => true,
  167. "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2" => true,
  168. 'SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"' => true,
  169. // Several objects in a row...
  170. //
  171. 'SELECT A FROM A' => true,
  172. 'SELECT A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  173. 'SELECT A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  174. 'SELECT B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  175. 'SELECT A,B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  176. 'SELECT A, B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  177. 'SELECT B,A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
  178. 'SELECT A, B,C FROM A JOIN B ON A.myB = B.id' => false,
  179. 'SELECT C FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => false,
  180. 'SELECT A JOIN B ON A.myB BELOW B.id WHERE A.col1 = 2' => true,
  181. '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,
  182. '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,
  183. '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,
  184. '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,
  185. '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,
  186. );
  187. $iErrors = 0;
  188. foreach($aQueries as $sQuery => $bIsCorrectQuery)
  189. {
  190. $sIsOk = $bIsCorrectQuery ? 'good' : 'bad';
  191. echo "<h4>Testing query: $sQuery ($sIsOk)</h4>\n";
  192. try
  193. {
  194. $bRet = $this->TestQuery($sQuery, $bIsCorrectQuery);
  195. }
  196. catch(Exception $e)
  197. {
  198. $this->m_aErrors[] = "Exception: ".$e->getMessage();
  199. $bRet = false;
  200. }
  201. if (!$bRet) $iErrors++;
  202. }
  203. return ($iErrors == 0);
  204. }
  205. }
  206. class TestCSVParser extends TestFunction
  207. {
  208. static public function GetName() {return 'Check CSV parsing';}
  209. static public function GetDescription() {return 'Loads a set of CSV data';}
  210. public function DoExecute()
  211. {
  212. $sDataFile = '?field1?;?field2?;?field3?
  213. ?a?;?b?;?c?
  214. a;b;c
  215. ? a ? ; ? b ? ; ? c ?
  216. a ; b ; c
  217. ??;??;??
  218. ;;
  219. ?a"?;?b?;?c?
  220. ?a1
  221. a2?;?b?;?c?
  222. ?a1,a2?;?b?;?c?
  223. ?a?;?b?;?c1,",c2
  224. ,c3?
  225. ?a?;?b?;?ouf !?
  226. Espace sur la fin ; 1234; e@taloc.com ';
  227. self::DumpVariable($sDataFile);
  228. $aExpectedResult = array(
  229. //array('field1', 'field2', 'field3'),
  230. array('a', 'b', 'c'),
  231. array('a', 'b', 'c'),
  232. array(' a ', ' b ', ' c '),
  233. array('a', 'b', 'c'),
  234. array('', '', ''),
  235. array('', '', ''),
  236. array('a"', 'b', 'c'),
  237. array("a1\na2", 'b', 'c'),
  238. array('a1,a2', 'b', 'c'),
  239. array('a', 'b', "c1,\",c2\n,c3"),
  240. array('a', 'b', 'ouf !'),
  241. array('Espace sur la fin', '1234', 'e@taloc.com'),
  242. );
  243. $oCSVParser = new CSVParser($sDataFile, ';', '?');
  244. $aData = $oCSVParser->ToArray(1, null, 0);
  245. $iIssues = 0;
  246. echo "<table border=\"1\">\n";
  247. foreach ($aData as $iRow => $aRow)
  248. {
  249. echo "<tr>\n";
  250. foreach ($aRow as $iCol => $sCell)
  251. {
  252. if (empty($sCell))
  253. {
  254. $sCellValue = '&nbsp;';
  255. }
  256. else
  257. {
  258. $sCellValue = htmlentities($sCell, ENT_QUOTES, 'UTF-8');
  259. }
  260. if (!isset($aExpectedResult[$iRow][$iCol]))
  261. {
  262. $iIssues++;
  263. $sCellValue = "<span style =\"color: red; background-color: grey;\">$sCellValue</span>";
  264. }
  265. elseif ($aExpectedResult[$iRow][$iCol] != $sCell)
  266. {
  267. $iIssues++;
  268. $sCellValue = "<span style =\"color: red; background-color: lightgrey;\">$sCellValue</span>, expecting '<span style =\"color: green; background-color: lightgrey;\">".$aExpectedResult[$iRow][$iCol]."</span>'";
  269. }
  270. echo "<td><pre>$sCellValue</pre></td>";
  271. }
  272. echo "</tr>\n";
  273. }
  274. echo "</table>\n";
  275. return ($iIssues > 0);
  276. }
  277. }
  278. class TestGenericItoMyModel extends TestBizModelGeneric
  279. {
  280. static public function GetName()
  281. {
  282. return 'Generic RO test on '.self::GetConfigFile();
  283. }
  284. static public function GetConfigFile() {return '/config-test-mymodel.php';}
  285. }
  286. class TestGenericItopBigModel extends TestBizModelGeneric
  287. {
  288. static public function GetName()
  289. {
  290. return 'Generic RO test on '.self::GetConfigFile();
  291. }
  292. static public function GetConfigFile() {return '/config-test-itopv06.php';}
  293. }
  294. class TestUserRightsMatrixItop extends TestUserRights
  295. {
  296. static public function GetName()
  297. {
  298. return 'User rights test on user rights matrix';
  299. }
  300. static public function GetDescription()
  301. {
  302. return 'blah blah blah';
  303. }
  304. public function DoPrepare()
  305. {
  306. parent::DoPrepare();
  307. MetaModel::Startup('../config-test-itopv06.php');
  308. }
  309. protected function DoExecute()
  310. {
  311. $sUser = 'Romain';
  312. echo "<p>Totor: ".(UserRights::CheckCredentials('Totor', 'toto') ? 'ok' : 'NO')."</p>\n";
  313. echo "<p>Romain: ".(UserRights::CheckCredentials('Romain', 'toto') ? 'ok' : 'NO')."</p>\n";
  314. echo "<p>User: ".UserRights::GetUser()."</p>\n";
  315. echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
  316. echo "<p>Denis (impersonate) : ".(UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO')."</p>\n";
  317. echo "<p>User: ".UserRights::GetUser()."</p>\n";
  318. echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
  319. $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization"));
  320. echo "<p>IsActionAllowed...".(UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  321. echo "<p>IsStimulusAllowed...".(UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  322. echo "<p>IsActionAllowedOnAttribute...".(UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
  323. return true;
  324. }
  325. }
  326. ///////////////////////////////////////////////////////////////////////////
  327. // Test a complex biz model on the fly
  328. ///////////////////////////////////////////////////////////////////////////
  329. class TestMyBizModel extends TestBizModel
  330. {
  331. static public function GetName()
  332. {
  333. return 'A series of tests on a weird business model';
  334. }
  335. static public function GetDescription()
  336. {
  337. return 'Attempts various operations and build complex queries';
  338. }
  339. static public function GetConfigFile() {return '/config-test-mymodel.php';}
  340. function test_linksinfo()
  341. {
  342. echo "<h4>Enum links</h4>";
  343. self::DumpVariable(MetaModel::EnumReferencedClasses("cmdbTeam"));
  344. self::DumpVariable(MetaModel::EnumReferencingClasses("Organization"));
  345. self::DumpVariable(MetaModel::EnumLinkingClasses());
  346. self::DumpVariable(MetaModel::EnumLinkingClasses("cmdbContact"));
  347. self::DumpVariable(MetaModel::EnumLinkingClasses("cmdWorkshop"));
  348. self::DumpVariable(MetaModel::GetLinkLabel("Liens_entre_contacts_et_workshop", "toworkshop"));
  349. }
  350. function test_list_attributes()
  351. {
  352. echo "<h4>List attributes</h4>";
  353. foreach(MetaModel::ListAttributeDefs("cmdbTeam") as $sAttCode=>$oAttDef)
  354. {
  355. echo $oAttDef->GetLabel()." / ".$oAttDef->GetDescription()." / ".$oAttDef->GetType()."</br>\n";
  356. }
  357. }
  358. function test_search()
  359. {
  360. echo "<h4>Two searches</h4>";
  361. $oFilterAllDevs = new DBObjectSearch("cmdbTeam");
  362. $oAllDevs = new DBObjectSet($oFilterAllDevs);
  363. echo "Found ".$oAllDevs->Count()." items.</br>\n";
  364. while ($oDev = $oAllDevs->Fetch())
  365. {
  366. $aValues = array();
  367. foreach(MetaModel::GetAttributesList($oAllDevs->GetClass()) as $sAttCode)
  368. {
  369. $aValues[] = MetaModel::GetLabel(get_class($oDev), $sAttCode)." (".MetaModel::GetDescription(get_class($oDev), $sAttCode).") = ".$oDev->GetAsHTML($sAttCode);
  370. }
  371. echo $oDev->GetKey()." => ".implode(", ", $aValues)."</br>\n";
  372. }
  373. // a second one
  374. $oMyFilter = new DBObjectSearch("cmdbContact");
  375. //$oMyFilter->AddCondition("name", "aii", "Finishes with");
  376. $oMyFilter->AddCondition("name", "aii");
  377. $this->search_and_show_list($oMyFilter);
  378. }
  379. function test_reload()
  380. {
  381. echo "<h4>Reload</h4>";
  382. $team = MetaModel::GetObject("cmdbContact", "2");
  383. echo "Chargement de l'attribut headcount: {$team->Get("headcount")}</br>\n";
  384. self::DumpVariable($team);
  385. }
  386. function test_setattribute()
  387. {
  388. echo "<h4>Set attribute and update</h4>";
  389. $team = MetaModel::GetObject("cmdbTeam", "2");
  390. $team->Set("headcount", rand(1,1000));
  391. $team->Set("email", "Luis ".rand(9,250));
  392. self::DumpVariable($team->ListChanges());
  393. echo "New headcount = {$team->Get("headcount")}</br>\n";
  394. echo "Computed name = {$team->Get("name")}</br>\n";
  395. $oMyChange = MetaModel::NewObject("CMDBChange");
  396. $oMyChange->Set("date", time());
  397. $oMyChange->Set("userinfo", "test_setattribute / Made by robot #".rand(1,100));
  398. $iChangeId = $oMyChange->DBInsert();
  399. //MetaModel::StartDebugQuery();
  400. $team->DBUpdateTracked($oMyChange);
  401. //MetaModel::StopDebugQuery();
  402. echo "<h4>Check the modified team</h4>";
  403. $oTeam = MetaModel::GetObject("cmdbTeam", "2");
  404. self::DumpVariable($oTeam);
  405. }
  406. function test_newobject()
  407. {
  408. $oMyChange = MetaModel::NewObject("CMDBChange");
  409. $oMyChange->Set("date", time());
  410. $oMyChange->Set("userinfo", "test_newobject / Made by robot #".rand(1,100));
  411. $iChangeId = $oMyChange->DBInsert();
  412. echo "<h4>Create a new object (team)</h4>";
  413. $oNewTeam = MetaModel::NewObject("cmdbTeam");
  414. $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
  415. $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
  416. $oNewTeam->Set("email", null);
  417. $oNewTeam->Set("owner", "ITOP");
  418. $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
  419. $iId = $oNewTeam->DBInsertTracked($oMyChange);
  420. echo "Created new team: $iId</br>";
  421. echo "<h4>Delete team #$iId</h4>";
  422. $oTeam = MetaModel::GetObject("cmdbTeam", $iId);
  423. $oTeam->DBDeleteTracked($oMyChange);
  424. echo "Deleted team: $iId</br>";
  425. self::DumpVariable($oTeam);
  426. }
  427. function test_updatecolumn()
  428. {
  429. $oMyChange = MetaModel::NewObject("CMDBChange");
  430. $oMyChange->Set("date", time());
  431. $oMyChange->Set("userinfo", "test_updatecolumn / Made by robot #".rand(1,100));
  432. $iChangeId = $oMyChange->DBInsert();
  433. $sNewEmail = "updatecol".rand(9,250)."@quedlaballe.com";
  434. echo "<h4>Update a the email: set to '$sNewEmail'</h4>";
  435. $oMyFilter = new DBObjectSearch("cmdbContact");
  436. $oMyFilter->AddCondition("name", "o", "Contains");
  437. echo "Candidates before:</br>";
  438. $this->search_and_show_list($oMyFilter);
  439. MetaModel::BulkUpdateTracked($oMyChange, $oMyFilter, array("email" => $sNewEmail));
  440. echo "Candidates after:</br>";
  441. $this->search_and_show_list($oMyFilter);
  442. }
  443. function test_error()
  444. {
  445. trigger_error("Stop requested", E_USER_ERROR);
  446. }
  447. function test_changetracking()
  448. {
  449. echo "<h4>Create a change</h4>";
  450. $oMyChange = MetaModel::NewObject("CMDBChange");
  451. $oMyChange->Set("date", time());
  452. $oMyChange->Set("userinfo", "Made by robot #".rand(1,100));
  453. $iChangeId = $oMyChange->DBInsert();
  454. echo "Created new change: $iChangeId</br>";
  455. self::DumpVariable($oMyChange);
  456. echo "<h4>Create a new object (team)</h4>";
  457. $oNewTeam = MetaModel::NewObject("cmdbTeam");
  458. $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
  459. $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
  460. $oNewTeam->Set("email", null);
  461. $oNewTeam->Set("owner", "ITOP");
  462. $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
  463. $iId = $oNewTeam->DBInsertTracked($oMyChange);
  464. echo "Created new team: $iId</br>";
  465. echo "<h4>Delete team #$iId</h4>";
  466. $oTeam = MetaModel::GetObject("cmdbTeam", $iId);
  467. $oTeam->DBDeleteTracked($oMyChange);
  468. echo "Deleted team: $iId</br>";
  469. self::DumpVariable($oTeam);
  470. }
  471. function test_zlist()
  472. {
  473. echo "<h4>Test ZLists</h4>";
  474. $aZLists = MetaModel::EnumZLists();
  475. foreach ($aZLists as $sListCode)
  476. {
  477. $aListInfos = MetaModel::GetZListInfo($sListCode);
  478. echo "<h4>List '".$sListCode."' (".$aListInfos["description"].") of type '".$aListInfos["type"]."'</h5>\n";
  479. foreach (MetaModel::GetSubclasses("cmdbObjectHomeMade") as $sKlass)
  480. {
  481. $aItems = MetaModel::FlattenZlist(MetaModel::GetZListItems($sKlass, $sListCode));
  482. if (count($aItems) == 0) continue;
  483. echo "$sKlass - $sListCode : {".implode(", ", $aItems)."}</br>\n";
  484. }
  485. }
  486. echo "<h4>IsAttributeInZList()... </h4>";
  487. echo "Liens_entre_contacts_et_workshop::ws_info in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "ws_info") ? "yes" : "no")."</br>\n";
  488. echo "Liens_entre_contacts_et_workshop::toworkshop in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "toworkshop") ? "yes" : "no")."</br>\n";
  489. }
  490. function test_pkey()
  491. {
  492. echo "<h4>Test search on pkey</h4>";
  493. $sExpr1 = "SELECT cmdbContact WHERE id IN (40, 42)";
  494. $sExpr2 = "SELECT cmdbContact WHERE IN NOT IN (40, 42)";
  495. $this->search_and_show_list_from_oql($sExpr1);
  496. $this->search_and_show_list_from_oql($sExpr2);
  497. echo "Et maintenant, on fusionne....</br>\n";
  498. $oSet1 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr1));
  499. $oSet2 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr2));
  500. $oIntersect = $oSet1->CreateIntersect($oSet2);
  501. $oDelta = $oSet1->CreateDelta($oSet2);
  502. $oMerge = clone $oSet1;
  503. $oMerge->Merge($oSet2);
  504. $oMerge->Merge($oSet2);
  505. echo "Set1 - Found ".$oSet1->Count()." items.</br>\n";
  506. echo "Set2 - Found ".$oSet2->Count()." items.</br>\n";
  507. echo "Intersect - Found ".$oIntersect->Count()." items.</br>\n";
  508. echo "Delta - Found ".$oDelta->Count()." items.</br>\n";
  509. echo "Merge - Found ".$oMerge->Count()." items.</br>\n";
  510. //$this->show_list($oObjSet);
  511. }
  512. function test_relations()
  513. {
  514. echo "<h4>Test relations</h4>";
  515. //self::DumpVariable(MetaModel::EnumRelationQueries("cmdbObjectHomeMade", "Potes"));
  516. self::DumpVariable(MetaModel::EnumRelationQueries("cmdbContact", "Potes"));
  517. $iMaxDepth = 9;
  518. echo "Max depth = $iMaxDepth</br>\n";
  519. $oObj = MetaModel::GetObject("cmdbContact", 18);
  520. $aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth);
  521. echo $oObj->Get('name')." has some 'Potes'...</br>\n";
  522. foreach ($aRels as $sClass => $aObjs)
  523. {
  524. echo "$sClass, count = ".count($aObjs)." =&gt; ".implode(', ', array_keys($aObjs))."</br>\n";
  525. $oObjectSet = CMDBObjectSet::FromArray($sClass, $aObjs);
  526. $this->show_list($oObjectSet);
  527. }
  528. echo "<h4>Test relations - same results, by the mean of a OQL</h4>";
  529. $this->search_and_show_list_from_oql("cmdbContact: RELATED (Potes, $iMaxDepth) TO (cmdbContact: pkey = 18)");
  530. }
  531. function test_linkedset()
  532. {
  533. echo "<h4>Linked set attributes</h4>\n";
  534. $oObj = MetaModel::GetObject("cmdbContact", 18);
  535. echo "<h5>Current workshops</h5>\n";
  536. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  537. $this->show_list($oSetWorkshopsCurr);
  538. echo "<h5>Setting workshops</h5>\n";
  539. $oNewLink = new cmdbLiens();
  540. $oNewLink->Set('toworkshop', 2);
  541. $oNewLink->Set('function', 'mafonctioooon');
  542. $oNewLink->Set('a1', 'tralala1');
  543. $oNewLink->Set('a2', 'F7M');
  544. $oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink));
  545. $oObj->Set("myworkshops", $oSetWorkshops);
  546. $this->show_list($oSetWorkshops);
  547. echo "<h5>New workshops</h5>\n";
  548. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  549. $this->show_list($oSetWorkshopsCurr);
  550. $oMyChange = MetaModel::NewObject("CMDBChange");
  551. $oMyChange->Set("date", time());
  552. $oMyChange->Set("userinfo", "test_linkedset / Made by robot #".rand(1,100));
  553. $iChangeId = $oMyChange->DBInsert();
  554. $oObj->DBUpdateTracked($oMyChange);
  555. $oObj = MetaModel::GetObject("cmdbContact", 18);
  556. echo "<h5>After the write</h5>\n";
  557. $oSetWorkshopsCurr = $oObj->Get("myworkshops");
  558. $this->show_list($oSetWorkshopsCurr);
  559. }
  560. function test_object_lifecycle()
  561. {
  562. echo "<h4>Test object lifecycle</h4>";
  563. self::DumpVariable(MetaModel::GetStateAttributeCode("cmdbContact"));
  564. self::DumpVariable(MetaModel::EnumStates("cmdbContact"));
  565. self::DumpVariable(MetaModel::EnumStimuli("cmdbContact"));
  566. foreach(MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef)
  567. {
  568. echo "<p>Transition from <strong>$sStateCode</strong></p>\n";
  569. self::DumpVariable(MetaModel::EnumTransitions("cmdbContact", $sStateCode));
  570. }
  571. $oObj = MetaModel::GetObject("cmdbContact", 18);
  572. echo "Current state: ".$oObj->GetState()."... let's go to school...";
  573. self::DumpVariable($oObj->EnumTransitions());
  574. $oObj->ApplyStimulus("toschool");
  575. echo "New state: ".$oObj->GetState()."... let's get older...";
  576. self::DumpVariable($oObj->EnumTransitions());
  577. $oObj->ApplyStimulus("raise");
  578. echo "New state: ".$oObj->GetState()."... let's try to go further... (should give an error)";
  579. self::DumpVariable($oObj->EnumTransitions());
  580. $oObj->ApplyStimulus("raise"); // should give an error
  581. }
  582. protected function DoExecute()
  583. {
  584. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  585. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  586. //$this->test_linksinfo();
  587. //$this->test_list_attributes();
  588. //$this->test_search();
  589. //$this->test_reload();
  590. //$this->test_newobject();
  591. $this->test_setattribute();
  592. //$this->test_updatecolumn();
  593. //$this->test_error();
  594. //$this->test_changetracking();
  595. $this->test_zlist();
  596. $this->test_OQL();
  597. //$this->test_pkey();
  598. $this->test_relations();
  599. $this->test_linkedset();
  600. $this->test_object_lifecycle();
  601. }
  602. }
  603. ///////////////////////////////////////////////////////////////////////////
  604. // Test a complex biz model on the fly
  605. ///////////////////////////////////////////////////////////////////////////
  606. abstract class MyFarm extends TestBizModel
  607. {
  608. static public function GetConfigFile() {return '/config-test-farm.php';}
  609. protected function DoPrepare()
  610. {
  611. parent::DoPrepare();
  612. $this->ResetDB();
  613. MetaModel::DBCheckIntegrity();
  614. }
  615. protected function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth)
  616. {
  617. $oNew = MetaModel::NewObject('Mammal');
  618. $oNew->Set('species', $sSpecies);
  619. $oNew->Set('sex', $sSex);
  620. $oNew->Set('speed', $iSpeed);
  621. $oNew->Set('mother', $iMotherid);
  622. $oNew->Set('father', $iFatherId);
  623. $oNew->Set('name', $sName);
  624. $oNew->Set('height', $iHeight);
  625. $oNew->Set('birth', $sBirth);
  626. return $this->ObjectToDB($oNew);
  627. }
  628. protected function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId)
  629. {
  630. $oNew = MetaModel::NewObject('Bird');
  631. $oNew->Set('species', $sSpecies);
  632. $oNew->Set('sex', $sSex);
  633. $oNew->Set('speed', $iSpeed);
  634. $oNew->Set('mother', $iMotherid);
  635. $oNew->Set('father', $iFatherId);
  636. return $this->ObjectToDB($oNew);
  637. }
  638. protected function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed)
  639. {
  640. $oNew = MetaModel::NewObject('FlyingBird');
  641. $oNew->Set('species', $sSpecies);
  642. $oNew->Set('sex', $sSex);
  643. $oNew->Set('speed', $iSpeed);
  644. $oNew->Set('mother', $iMotherid);
  645. $oNew->Set('father', $iFatherId);
  646. $oNew->Set('flyingspeed', $iFlyingSpeed);
  647. return $this->ObjectToDB($oNew);
  648. }
  649. private function InsertGroup($sName, $iLeaderId)
  650. {
  651. $oNew = MetaModel::NewObject('Group');
  652. $oNew->Set('name', $sName);
  653. $oNew->Set('leader', $iLeaderId);
  654. $iId = $oNew->DBInsertNoReload();
  655. return $iId;
  656. }
  657. }
  658. class TestQueriesOnFarm extends MyFarm
  659. {
  660. static public function GetName()
  661. {
  662. return 'Farm test';
  663. }
  664. static public function GetDescription()
  665. {
  666. return 'A series of tests on the farm business model (SQL generation)';
  667. }
  668. protected function CheckQuery($sQuery, $bIsCorrectQuery)
  669. {
  670. if ($bIsCorrectQuery)
  671. {
  672. echo "<h4 style=\"color:green;\">$sQuery</h4>\n";
  673. }
  674. else
  675. {
  676. echo "<h4 style=\"color:red;\">$sQuery</h3>\n";
  677. }
  678. try
  679. {
  680. //$oOql = new OqlInterpreter($sQuery);
  681. //$oTrash = $oOql->ParseObjectQuery();
  682. //self::DumpVariable($oTrash, true);
  683. $oMyFilter = DBObjectSearch::FromOQL($sQuery);
  684. }
  685. catch (OQLException $oOqlException)
  686. {
  687. if ($bIsCorrectQuery)
  688. {
  689. echo "<p>More info on this unexpected failure:<br/>".$oOqlException->getHtmlDesc()."</p>\n";
  690. throw $oOqlException;
  691. return false;
  692. }
  693. else
  694. {
  695. // Everything is fine :-)
  696. echo "<p>More info on this expected failure:\n";
  697. echo "<ul>\n";
  698. echo "<li>".get_class($oOqlException)."</li>\n";
  699. echo "<li>".$oOqlException->getMessage()."</li>\n";
  700. echo "<li>".$oOqlException->getHtmlDesc()."</li>\n";
  701. echo "</ul>\n";
  702. echo "</p>\n";
  703. return true;
  704. }
  705. }
  706. // The query was correctly parsed, was it expected to be correct ?
  707. if (!$bIsCorrectQuery)
  708. {
  709. throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
  710. return false;
  711. }
  712. echo "<p>To OQL: ".$oMyFilter->ToOQL()."</p>";
  713. $this->search_and_show_list($oMyFilter);
  714. //echo "<p>first pass<p>\n";
  715. //self::DumpVariable($oMyFilter, true);
  716. $sQuery1 = MetaModel::MakeSelectQuery($oMyFilter);
  717. //echo "<p>second pass<p>\n";
  718. //self::DumpVariable($oMyFilter, true);
  719. //$sQuery1 = MetaModel::MakeSelectQuery($oMyFilter);
  720. $sSerialize = $oMyFilter->serialize();
  721. echo "<p>Serialized:$sSerialize</p>\n";
  722. $oFilter2 = DBObjectSearch::unserialize($sSerialize);
  723. try
  724. {
  725. $sQuery2 = MetaModel::MakeSelectQuery($oFilter2);
  726. }
  727. catch (Exception $e)
  728. {
  729. echo "<p>Could not compute the query after unserialize</p>\n";
  730. echo "<p>Query 1: $sQuery1</p>\n";
  731. MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
  732. throw $e;
  733. }
  734. //if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same!
  735. if ($sQuery1 != $sQuery2)
  736. {
  737. echo "<p>serialize/unserialize mismatch :-(</p>\n";
  738. MyHelpers::var_cmp_html($sQuery1, $sQuery2);
  739. MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
  740. return false;
  741. }
  742. return true;
  743. }
  744. protected function DoExecute()
  745. {
  746. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  747. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  748. echo "<h3>Create protagonists...</h3>";
  749. $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
  750. $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
  751. $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
  752. $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
  753. $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
  754. $this->InsertBird('rooster', 'male', 12, 0, 0);
  755. $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
  756. // Benchmarking
  757. //
  758. if (false)
  759. {
  760. define ('COUNT_BENCHMARK', 10);
  761. echo "<h3>Parsing a long query, ".COUNT_BENCHMARK." times</h3>";
  762. $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)";
  763. $fStart = MyHelpers::getmicrotime();
  764. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  765. {
  766. $oMyFilter = DBObjectSearch::FromOQL($sQuery);
  767. }
  768. $fDuration = MyHelpers::getmicrotime() - $fStart;
  769. $fParsingDuration = $fDuration / COUNT_BENCHMARK;
  770. echo "<p>Mean time by op: $fParsingDuration</p>";
  771. }
  772. echo "<h3>Test queries...</h3>";
  773. $aQueries = array(
  774. 'SELECT Animal' => true,
  775. 'SELECT Animal WHERE Animal.pkey = 1' => false,
  776. 'SELECT Animal WHERE Animal.id = 1' => true,
  777. 'SELECT Aniiimal' => false,
  778. 'SELECTe Animal' => false,
  779. 'SELECT * FROM Animal' => false,
  780. 'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true,
  781. 'SELECT Animal AS zoo WHERE species = \'human\'' => true,
  782. 'SELECT Animal AS zoo WHERE espece = \'human\'' => false,
  783. 'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true,
  784. 'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false,
  785. 'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true,
  786. 'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true,
  787. 'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false,
  788. 'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true,
  789. 'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true,
  790. 'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true,
  791. 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
  792. 'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true,
  793. 'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true,
  794. 'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true,
  795. 'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true,
  796. 'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true,
  797. 'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true,
  798. 'SELECT Mammal AS m WHERE (1 + 2' => false,
  799. 'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true,
  800. 'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true,
  801. 'SELECT Mammal AS m WHERE 1/0' => true,
  802. 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
  803. 'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true,
  804. 'SELECT Group JOIN Animal ON Group.leader = Animal.id' => true,
  805. 'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true,
  806. 'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false,
  807. 'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false,
  808. 'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false,
  809. 'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false,
  810. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false,
  811. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true,
  812. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true,
  813. 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false,
  814. 'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false,
  815. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true,
  816. 'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false,
  817. 'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false,
  818. 'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false,
  819. 'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true,
  820. 'SELECT Group AS G WHERE G.leader_speed < 100000' => true,
  821. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
  822. 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true,
  823. 'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  824. 'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
  825. 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  826. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
  827. 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true,
  828. 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
  829. '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,
  830. '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,
  831. 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
  832. '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,
  833. 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
  834. 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true,
  835. '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,
  836. // Specifying multiple objects
  837. 'SELECT Animal FROM Animal' => true,
  838. 'SELECT yelele FROM Animal' => false,
  839. 'SELECT Animal FROM Animal AS A' => false,
  840. 'SELECT A FROM Animal AS A' => true,
  841. );
  842. //$aQueries = array(
  843. // 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
  844. //);
  845. foreach($aQueries as $sQuery => $bIsCorrect)
  846. {
  847. $this->CheckQuery($sQuery, $bIsCorrect);
  848. }
  849. return true;
  850. }
  851. }
  852. ///////////////////////////////////////////////////////////////////////////
  853. // Test data load
  854. ///////////////////////////////////////////////////////////////////////////
  855. class TestBulkChangeOnFarm extends TestBizModel
  856. {
  857. static public function GetName()
  858. {
  859. return 'Farm test - data load';
  860. }
  861. static public function GetDescription()
  862. {
  863. return 'Bulk load';
  864. }
  865. static public function GetConfigFile() {return '/config-test-farm.php';}
  866. protected function DoPrepare()
  867. {
  868. parent::DoPrepare();
  869. $this->ResetDB();
  870. MetaModel::DBCheckIntegrity();
  871. }
  872. protected function DoExecute()
  873. {
  874. // $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  875. // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  876. $oParser = new CSVParser("denomination,hauteur,age
  877. suzy,123,2009-01-01
  878. chita,456,
  879. ", ',', '"');
  880. $aData = $oParser->ToArray(1, array('_name', '_height', '_birth'));
  881. self::DumpVariable($aData);
  882. $oBulk = new BulkChange(
  883. 'Mammal',
  884. $aData,
  885. // attributes
  886. array('name' => '_name', 'height' => '_height', 'birth' => '_birth'),
  887. // ext keys
  888. array(),
  889. // reconciliation
  890. array('name')
  891. );
  892. $oMyChange = MetaModel::NewObject("CMDBChange");
  893. $oMyChange->Set("date", time());
  894. $oMyChange->Set("userinfo", "Testor");
  895. $iChangeId = $oMyChange->DBInsert();
  896. // echo "Created new change: $iChangeId</br>";
  897. echo "<h3>Planned for loading...</h3>";
  898. $aRes = $oBulk->Process();
  899. self::DumpVariable($aRes);
  900. echo "<h3>Go for loading...</h3>";
  901. $aRes = $oBulk->Process($oMyChange);
  902. self::DumpVariable($aRes);
  903. return;
  904. $oRawData = array(
  905. 'Mammal',
  906. array('species', 'sex', 'speed', 'mother', 'father', 'name', 'height', 'birth'),
  907. "human,male,23,0,0,romulus,192,1971
  908. human,male,23,0,0,remus,154,-50
  909. human,male,23,0,0,julius,160,-49
  910. human,female,23,0,0,cleopatra,142,-50
  911. pig,female,23,0,0,confucius,50,2003"
  912. );
  913. }
  914. }
  915. ///////////////////////////////////////////////////////////////////////////
  916. // Test data load
  917. ///////////////////////////////////////////////////////////////////////////
  918. class TestFullTextSearchOnFarm extends MyFarm
  919. {
  920. static public function GetName()
  921. {
  922. return 'Farm test - full text search';
  923. }
  924. static public function GetDescription()
  925. {
  926. return 'Focus on the full text search feature';
  927. }
  928. protected function DoExecute()
  929. {
  930. echo "<h3>Create protagonists...</h3>";
  931. $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
  932. $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
  933. $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
  934. $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
  935. $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
  936. $this->InsertBird('rooster', 'male', 12, 0, 0);
  937. $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
  938. echo "<h3>Search...</h3>";
  939. $oSearch = new DBObjectSearch('Mammal');
  940. $oSearch->AddCondition_FullText('manof');
  941. //$oResultSet = new DBObjectSet($oSearch);
  942. $this->search_and_show_list($oSearch);
  943. }
  944. }
  945. ///////////////////////////////////////////////////////////////////////////
  946. // Test queries
  947. ///////////////////////////////////////////////////////////////////////////
  948. class TestItopEfficiency extends TestBizModel
  949. {
  950. static public function GetName()
  951. {
  952. return 'Itop - benchmark';
  953. }
  954. static public function GetDescription()
  955. {
  956. return 'Measure time to perform the queries';
  957. }
  958. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  959. protected function DoBenchmark($sOqlQuery)
  960. {
  961. echo "<h3>Testing query: $sOqlQuery</h3>";
  962. $fStart = MyHelpers::getmicrotime();
  963. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  964. {
  965. $oFilter = DBObjectSearch::FromOQL($sOqlQuery);
  966. }
  967. $fDuration = MyHelpers::getmicrotime() - $fStart;
  968. $fParsingDuration = $fDuration / COUNT_BENCHMARK;
  969. $fStart = MyHelpers::getmicrotime();
  970. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  971. {
  972. $sSQL = MetaModel::MakeSelectQuery($oFilter);
  973. }
  974. $fDuration = MyHelpers::getmicrotime() - $fStart;
  975. $fBuildDuration = $fDuration / COUNT_BENCHMARK;
  976. $fStart = MyHelpers::getmicrotime();
  977. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  978. {
  979. $res = CMDBSource::Query($sSQL);
  980. }
  981. $fDuration = MyHelpers::getmicrotime() - $fStart;
  982. $fQueryDuration = $fDuration / COUNT_BENCHMARK;
  983. // The fetch could not be repeated with the same results
  984. // But we've seen so far that is was very very quick to exec
  985. // So it makes sense to benchmark it a single time
  986. $fStart = MyHelpers::getmicrotime();
  987. $aRow = CMDBSource::FetchArray($res);
  988. $fDuration = MyHelpers::getmicrotime() - $fStart;
  989. $fFetchDuration = $fDuration;
  990. $fStart = MyHelpers::getmicrotime();
  991. for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
  992. {
  993. $sOql = $oFilter->ToOQL();
  994. }
  995. $fDuration = MyHelpers::getmicrotime() - $fStart;
  996. $fToOqlDuration = $fDuration / COUNT_BENCHMARK;
  997. echo "<ul>\n";
  998. echo "<li>Parsing: $fParsingDuration</li>\n";
  999. echo "<li>Build: $fBuildDuration</li>\n";
  1000. echo "<li>Query: $fQueryDuration</li>\n";
  1001. echo "<li>Fetch: $fFetchDuration</li>\n";
  1002. echo "<li>ToOql: $fToOqlDuration</li>\n";
  1003. echo "</ul>\n";
  1004. // Everything but the ToOQL (wich is interesting, anyhow)
  1005. $fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration;
  1006. return array(
  1007. 'rows' => CMDBSource::NbRows($res),
  1008. 'duration (s)' => round($fTotal, 4),
  1009. 'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
  1010. 'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
  1011. 'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
  1012. 'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
  1013. 'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
  1014. 'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
  1015. );
  1016. }
  1017. protected function DoExecute()
  1018. {
  1019. define ('COUNT_BENCHMARK', 3);
  1020. echo "<p>The test will be repeated ".COUNT_BENCHMARK." times</p>";
  1021. $aQueries = array(
  1022. 'SELECT CMDBChangeOpSetAttribute',
  1023. 'SELECT CMDBChangeOpSetAttribute WHERE id=10',
  1024. 'SELECT CMDBChangeOpSetAttribute WHERE id=123456789',
  1025. 'SELECT CMDBChangeOpSetAttribute WHERE CMDBChangeOpSetAttribute.id=10',
  1026. 'SELECT Ticket',
  1027. 'SELECT Ticket WHERE id=1',
  1028. 'SELECT Person',
  1029. 'SELECT Person WHERE id=1',
  1030. 'SELECT Server',
  1031. 'SELECT Server WHERE id=1',
  1032. 'SELECT Incident JOIN Person ON Incident.agent_id = Person.id WHERE Person.id = 5',
  1033. );
  1034. $aStats = array();
  1035. foreach ($aQueries as $sOQL)
  1036. {
  1037. $aStats[$sOQL] = $this->DoBenchmark($sOQL);
  1038. }
  1039. $aData = array();
  1040. foreach ($aStats as $sOQL => $aResults)
  1041. {
  1042. $aValues = array();
  1043. $aValues['OQL'] = htmlentities($sOQL, ENT_QUOTES, 'UTF-8');
  1044. foreach($aResults as $sDesc => $sInfo)
  1045. {
  1046. $aValues[$sDesc] = htmlentities($sInfo, ENT_QUOTES, 'UTF-8');
  1047. }
  1048. $aData[] = $aValues;
  1049. }
  1050. echo MyHelpers::make_table_from_assoc_array($aData);
  1051. }
  1052. }
  1053. ///////////////////////////////////////////////////////////////////////////
  1054. // Benchmark queries
  1055. ///////////////////////////////////////////////////////////////////////////
  1056. class TestQueries extends TestBizModel
  1057. {
  1058. static public function GetName()
  1059. {
  1060. return 'Itop - queries';
  1061. }
  1062. static public function GetDescription()
  1063. {
  1064. return 'Try as many queries as possible';
  1065. }
  1066. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  1067. protected function DoBenchmark($sOqlQuery)
  1068. {
  1069. echo "<h5>Testing query: $sOqlQuery</h5>";
  1070. $fStart = MyHelpers::getmicrotime();
  1071. $oFilter = DBObjectSearch::FromOQL($sOqlQuery);
  1072. $fParsingDuration = MyHelpers::getmicrotime() - $fStart;
  1073. $fStart = MyHelpers::getmicrotime();
  1074. $sSQL = MetaModel::MakeSelectQuery($oFilter);
  1075. $fBuildDuration = MyHelpers::getmicrotime() - $fStart;
  1076. $fStart = MyHelpers::getmicrotime();
  1077. $res = CMDBSource::Query($sSQL);
  1078. $fQueryDuration = MyHelpers::getmicrotime() - $fStart;
  1079. // The fetch could not be repeated with the same results
  1080. // But we've seen so far that is was very very quick to exec
  1081. // So it makes sense to benchmark it a single time
  1082. $fStart = MyHelpers::getmicrotime();
  1083. $aRow = CMDBSource::FetchArray($res);
  1084. $fDuration = MyHelpers::getmicrotime() - $fStart;
  1085. $fFetchDuration = $fDuration;
  1086. $fStart = MyHelpers::getmicrotime();
  1087. $sOql = $oFilter->ToOQL();
  1088. $fToOqlDuration = MyHelpers::getmicrotime() - $fStart;
  1089. if (false)
  1090. {
  1091. echo "<ul style=\"font-size:smaller;\">\n";
  1092. echo "<li>Parsing: $fParsingDuration</li>\n";
  1093. echo "<li>Build: $fBuildDuration</li>\n";
  1094. echo "<li>Query: $fQueryDuration</li>\n";
  1095. echo "<li>Fetch: $fFetchDuration</li>\n";
  1096. echo "<li>ToOql: $fToOqlDuration</li>\n";
  1097. echo "</ul>\n";
  1098. }
  1099. // Everything but the ToOQL (wich is interesting, anyhow)
  1100. $fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration;
  1101. return array(
  1102. 'rows' => CMDBSource::NbRows($res),
  1103. 'duration (s)' => round($fTotal, 4),
  1104. 'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
  1105. 'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
  1106. 'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
  1107. 'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
  1108. 'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
  1109. 'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
  1110. );
  1111. }
  1112. protected function DoExecute()
  1113. {
  1114. $aQueries = array(
  1115. 'SELECT Person AS PP WHERE PP.friendlyname LIKE "%dali"',
  1116. 'SELECT Person AS PP WHERE PP.location_id_friendlyname LIKE "%ce ch%"',
  1117. 'SELECT Organization AS OO JOIN Person AS PP ON PP.org_id = OO.id',
  1118. 'SELECT lnkTeamToContact AS lnk JOIN Team AS T ON lnk.team_id = T.id',
  1119. 'SELECT lnkTeamToContact AS lnk JOIN Team AS T ON lnk.team_id = T.id JOIN Contact AS C ON lnk.contact_id = C.id',
  1120. 'SELECT Incident JOIN Person ON Incident.agent_id = Person.id WHERE Person.id = 5',
  1121. // this one is failing...
  1122. //'SELECT L, P FROM Person AS P JOIN Location AS L ON P.location_id = L.id',
  1123. );
  1124. foreach (MetaModel::GetClasses() as $sClass)
  1125. {
  1126. $aQueries[] = 'SELECT '.$sClass;
  1127. $aQueries[] = 'SELECT '.$sClass.' AS zz';
  1128. $aQueries[] = 'SELECT '.$sClass.' AS zz WHERE id = 1';
  1129. }
  1130. $aStats = array();
  1131. foreach ($aQueries as $sOQL)
  1132. {
  1133. $aStats[$sOQL] = $this->DoBenchmark($sOQL);
  1134. }
  1135. $aData = array();
  1136. foreach ($aStats as $sOQL => $aResults)
  1137. {
  1138. $aValues = array();
  1139. $aValues['OQL'] = htmlentities($sOQL, ENT_QUOTES, 'UTF-8');
  1140. foreach($aResults as $sDesc => $sInfo)
  1141. {
  1142. $aValues[$sDesc] = htmlentities($sInfo, ENT_QUOTES, 'UTF-8');
  1143. }
  1144. $aData[] = $aValues;
  1145. }
  1146. echo MyHelpers::make_table_from_assoc_array($aData);
  1147. }
  1148. }
  1149. ///////////////////////////////////////////////////////////////////////////
  1150. // Check programmaticaly built queries
  1151. ///////////////////////////////////////////////////////////////////////////
  1152. class TestQueriesByAPI extends TestBizModel
  1153. {
  1154. static public function GetName()
  1155. {
  1156. return 'Itop - queries build programmaticaly';
  1157. }
  1158. static public function GetDescription()
  1159. {
  1160. return 'Validate the DBObjectSearch API, through a set of complex (though realistic cases)';
  1161. }
  1162. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  1163. protected function DoExecute()
  1164. {
  1165. // Note: relying on eval() - after upgrading to PHP 5.3 we can move to closure (aka anonymous functions)
  1166. $aQueries = array(
  1167. 'Basic (validate the test)' => array(
  1168. 'search' => '
  1169. $oSearch = DBObjectSearch::FromOQL("SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE org_id = 2");
  1170. ',
  1171. 'oql' => 'SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE P.org_id = 2'
  1172. ),
  1173. 'Double constraint' => array(
  1174. 'search' => '
  1175. $oSearch = DBObjectSearch::FromOQL("SELECT Contact AS c");
  1176. $sClass = $oSearch->GetClass();
  1177. $sFilterCode = "org_id";
  1178. $oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
  1179. if ($oAttDef->IsExternalKey())
  1180. {
  1181. $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
  1182. if ($sHierarchicalKeyCode !== false)
  1183. {
  1184. $oFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1185. $oFilter->AddCondition("id", 2);
  1186. $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1187. $oHKFilter->AddCondition_PointingTo(clone $oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
  1188. $oSearch->AddCondition_PointingTo(clone $oHKFilter, $sFilterCode);
  1189. $oFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1190. $oFilter->AddCondition("id", 2);
  1191. $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass(), "ORGA");
  1192. $oHKFilter->AddCondition_PointingTo(clone $oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
  1193. $oSearch->AddCondition_PointingTo(clone $oHKFilter, $sFilterCode);
  1194. }
  1195. }
  1196. ',
  1197. 'oql' => 'SELECT Contact AS C JOIN Organization ???'
  1198. ),
  1199. 'Simplified issue' => array(
  1200. 'search' => '
  1201. $oSearch = DBObjectSearch::FromOQL("SELECT P FROM Organization AS O JOIN Person AS P ON P.org_id = O.id WHERE O.id = 2");
  1202. $oOrgSearch = new DBObjectSearch("Organization", "O2");
  1203. $oOrgSearch->AddCondition("id", 2);
  1204. $oSearch->AddCondition_PointingTo($oOrgSearch, "org_id");
  1205. ',
  1206. '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'
  1207. ),
  1208. );
  1209. foreach ($aQueries as $sQueryDesc => $aQuerySpec)
  1210. {
  1211. echo "<h2>Query $sQueryDesc</h2>\n";
  1212. echo "<p>Using code: ".highlight_string("<?php\n".trim($aQuerySpec['search'])."\n?".'>', true)."</p>\n";
  1213. echo "<p>Expected OQL: ".$aQuerySpec['oql']."</p>\n";
  1214. if (isset($oSearch))
  1215. {
  1216. unset($oSearch);
  1217. }
  1218. eval($aQuerySpec['search']);
  1219. $sResOQL = $oSearch->ToOQL();
  1220. echo "<p>Resulting OQL: ".$sResOQL."</p>\n";
  1221. echo "<pre>";
  1222. print_r($oSearch);
  1223. echo "</pre>";
  1224. $sSQL = MetaModel::MakeSelectQuery($oSearch);
  1225. $res = CMDBSource::Query($sSQL);
  1226. foreach (CMDBSource::ExplainQuery($sSQL) as $aRow)
  1227. {
  1228. }
  1229. }
  1230. // throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  1231. }
  1232. }
  1233. ///////////////////////////////////////////////////////////////////////////
  1234. // Test bulk load API
  1235. ///////////////////////////////////////////////////////////////////////////
  1236. class TestItopBulkLoad extends TestBizModel
  1237. {
  1238. static public function GetName()
  1239. {
  1240. return 'Itop - test BulkChange class';
  1241. }
  1242. static public function GetDescription()
  1243. {
  1244. return 'Execute a bulk change at the Core API level';
  1245. }
  1246. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  1247. protected function DoExecute()
  1248. {
  1249. $sLogin = 'testbulkload_'.time();
  1250. $oParser = new CSVParser("login,contactid->name,password,profile_list
  1251. _1_$sLogin,Picasso,secret1,profileid:10;reason:service manager|profileid->name:Problem Manager;'reason:toto;problem manager'
  1252. _2_$sLogin,Picasso,secret2,
  1253. ", ',', '"');
  1254. $aData = $oParser->ToArray(1, array('_login', '_contact_name', '_password', '_profiles'));
  1255. self::DumpVariable($aData);
  1256. $oUser = new UserLocal();
  1257. $oUser->Set('login', 'patator');
  1258. $oUser->Set('password', 'patator');
  1259. //$oUser->Set('contactid', 0);
  1260. //$oUser->Set('language', $sLanguage);
  1261. $aProfiles = array(
  1262. array(
  1263. 'profileid' => 10, // Service Manager
  1264. 'reason' => 'service manager',
  1265. ),
  1266. array(
  1267. 'profileid->name' => 'Problem Manager',
  1268. 'reason' => 'problem manager',
  1269. ),
  1270. );
  1271. $oBulk = new BulkChange(
  1272. 'UserLocal',
  1273. $aData,
  1274. // attributes
  1275. array('login' => '_login', 'password' => '_password', 'profile_list' => '_profiles'),
  1276. // ext keys
  1277. array('contactid' => array('name' => '_contact_name')),
  1278. // reconciliation
  1279. array('login'),
  1280. // Synchro - scope
  1281. "SELECT UserLocal",
  1282. // Synchro - set attribute on missing objects
  1283. array ('password' => 'terminated', 'login' => 'terminated'.time())
  1284. );
  1285. if (false)
  1286. {
  1287. $oMyChange = MetaModel::NewObject("CMDBChange");
  1288. $oMyChange->Set("date", time());
  1289. $oMyChange->Set("userinfo", "Testor");
  1290. $iChangeId = $oMyChange->DBInsert();
  1291. // echo "Created new change: $iChangeId</br>";
  1292. }
  1293. echo "<h3>Planned for loading...</h3>";
  1294. $aRes = $oBulk->Process();
  1295. self::DumpVariable($aRes);
  1296. if (false)
  1297. {
  1298. echo "<h3>Go for loading...</h3>";
  1299. $aRes = $oBulk->Process($oMyChange);
  1300. self::DumpVariable($aRes);
  1301. }
  1302. return;
  1303. }
  1304. }
  1305. ///////////////////////////////////////////////////////////////////////////
  1306. // Test data load
  1307. ///////////////////////////////////////////////////////////////////////////
  1308. class TestImportREST extends TestWebServices
  1309. {
  1310. static public function GetName()
  1311. {
  1312. return 'CSV import (REST)';
  1313. }
  1314. static public function GetDescription()
  1315. {
  1316. return 'Test various options and fonctionality of import.php';
  1317. }
  1318. protected function DoExecSingleLoad($aLoadSpec, $iTestId = null)
  1319. {
  1320. $sCsvData = $aLoadSpec['csvdata'];
  1321. echo "<div style=\"padding: 10;\">\n";
  1322. if (is_null($iTestId))
  1323. {
  1324. echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aLoadSpec['desc']}</h3>\n";
  1325. }
  1326. else
  1327. {
  1328. echo "<h3 style=\"background-color: #ddddff; padding: 10;\"><a href=\"?todo=exec&testid=TestImportREST&subtests=$iTestId\">$iTestId</a> - {$aLoadSpec['desc']}</h3>\n";
  1329. }
  1330. $aPostData = array('csvdata' => $sCsvData);
  1331. $aGetParams = array();
  1332. $aGetParamReport = array();
  1333. foreach($aLoadSpec['args'] as $sArg => $sValue)
  1334. {
  1335. $aGetParams[] = $sArg.'='.urlencode($sValue);
  1336. $aGetParamReport[] = $sArg.'='.$sValue;
  1337. }
  1338. $sGetParams = implode('&', $aGetParams);
  1339. $sLogin = isset($aLoadSpec['login']) ? $aLoadSpec['login'] : 'admin';
  1340. $sPassword = isset($aLoadSpec['password']) ? $aLoadSpec['password'] : 'admin';
  1341. $sRes = self::DoPostRequestAuth('../webservices/import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
  1342. $sArguments = implode('<br/>', $aGetParamReport);
  1343. if (strlen($sCsvData) > 5000)
  1344. {
  1345. $sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
  1346. }
  1347. else
  1348. {
  1349. $sCsvDataViewable = $sCsvData;
  1350. }
  1351. echo "<div style=\"\">\n";
  1352. echo " <div style=\"float:left; width:20%; padding:5; background-color:#eeeeff;\">\n";
  1353. echo " $sArguments\n";
  1354. echo " </div>\n";
  1355. echo " <div style=\"float:right; width:75%; padding:5; background-color:#eeeeff\">\n";
  1356. echo " <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
  1357. echo " </div>\n";
  1358. echo "</div>\n";
  1359. echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
  1360. echo "</div>\n";
  1361. }
  1362. protected function DoExecute()
  1363. {
  1364. $aLoads = array(
  1365. array(
  1366. 'desc' => 'Missing class',
  1367. 'login' => 'admin',
  1368. 'password' => 'admin',
  1369. 'args' => array(
  1370. ),
  1371. 'csvdata' => "xxx",
  1372. ),
  1373. array(
  1374. 'desc' => 'Wrong class',
  1375. 'login' => 'admin',
  1376. 'password' => 'admin',
  1377. 'args' => array(
  1378. 'class' => 'toto',
  1379. ),
  1380. 'csvdata' => "xxx",
  1381. ),
  1382. array(
  1383. 'desc' => 'Wrong output type',
  1384. 'login' => 'admin',
  1385. 'password' => 'admin',
  1386. 'args' => array(
  1387. 'class' => 'NetworkDevice',
  1388. 'output' => 'onthefly',
  1389. ),
  1390. 'csvdata' => "xxx",
  1391. ),
  1392. array(
  1393. 'desc' => 'Weird format, working anyhow...',
  1394. 'login' => 'admin',
  1395. 'password' => 'admin',
  1396. 'args' => array(
  1397. 'class' => 'Server',
  1398. 'output' => 'details',
  1399. 'separator' => '*',
  1400. 'qualifier' => '@',
  1401. 'reconciliationkeys' => 'org_id,name',
  1402. ),
  1403. 'csvdata' => 'name*org_id
  1404. server01*2
  1405. @server02@@combodo@* 2
  1406. server45*99',
  1407. ),
  1408. array(
  1409. 'desc' => 'Load an organization',
  1410. 'login' => 'admin',
  1411. 'password' => 'admin',
  1412. 'args' => array(
  1413. 'class' => 'Organization',
  1414. 'output' => 'details',
  1415. 'separator' => ';',
  1416. 'reconciliationkeys' => '',
  1417. ),
  1418. 'csvdata' => "name;code\nWorldCompany;WCY",
  1419. ),
  1420. array(
  1421. 'desc' => 'Load a location',
  1422. 'login' => 'admin',
  1423. 'password' => 'admin',
  1424. 'args' => array(
  1425. 'class' => 'Location',
  1426. 'output' => 'details',
  1427. 'separator' => ';',
  1428. 'reconciliationkeys' => '',
  1429. ),
  1430. 'csvdata' => "name;org_id;address\nParis;1;Centre de la Franca",
  1431. ),
  1432. array(
  1433. 'desc' => 'Load a person',
  1434. 'login' => 'admin',
  1435. 'password' => 'admin',
  1436. 'args' => array(
  1437. 'class' => 'Person',
  1438. 'output' => 'details',
  1439. 'separator' => ';',
  1440. 'reconciliationkeys' => '',
  1441. ),
  1442. 'csvdata' => "email;name;first_name;org_id;phone\njohn.foo@starac.com;Foo;John;1;+33(1)23456789",
  1443. ),
  1444. array(
  1445. 'desc' => 'Load a person - wrong email format',
  1446. 'login' => 'admin',
  1447. 'password' => 'admin',
  1448. 'args' => array(
  1449. 'class' => 'Person',
  1450. 'output' => 'details',
  1451. 'separator' => ';',
  1452. 'reconciliationkeys' => '',
  1453. ),
  1454. 'csvdata' => "email;name;first_name;org_id\nemailPASbon;Foo;John;1",
  1455. ),
  1456. array(
  1457. 'desc' => 'Load a team',
  1458. 'login' => 'admin',
  1459. 'password' => 'admin',
  1460. 'args' => array(
  1461. 'class' => 'Team',
  1462. 'output' => 'details',
  1463. 'separator' => ';',
  1464. 'reconciliationkeys' => '',
  1465. ),
  1466. 'csvdata' => "name;org_id;location_name\nSquadra Azzura2;1;Paris",
  1467. ),
  1468. array(
  1469. 'desc' => 'Load server',
  1470. 'login' => 'admin',
  1471. 'password' => 'admin',
  1472. 'args' => array(
  1473. 'class' => 'Server',
  1474. 'output' => 'details',
  1475. 'separator' => ';',
  1476. 'reconciliationkeys' => '',
  1477. ),
  1478. '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",
  1479. ),
  1480. array(
  1481. 'desc' => 'Load server (column header localized in english)',
  1482. 'login' => 'admin',
  1483. 'password' => 'admin',
  1484. 'args' => array(
  1485. 'class' => 'Server',
  1486. 'output' => 'details',
  1487. 'separator' => ';',
  1488. 'reconciliationkeys' => '',
  1489. ),
  1490. '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",
  1491. ),
  1492. array(
  1493. 'desc' => 'Load server (directly from Export results)',
  1494. 'login' => 'admin',
  1495. 'password' => 'admin',
  1496. 'args' => array(
  1497. 'class' => 'Server',
  1498. 'output' => 'details',
  1499. 'reconciliationkeys' => '',
  1500. ),
  1501. '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
  1502. 1,"dbserver1.demo.com","production",2,"Demo","medium","HP","DL380","","","ouille
  1503. [[Server:webserver.demo.com]]",1,"Grenoble","","10.1.1.10","255.255.255.0","2","16Gb","120Gb","Linux","Debian (Lenny)"',
  1504. ),
  1505. array(
  1506. 'desc' => 'Load server - wrong value for status',
  1507. 'login' => 'admin',
  1508. 'password' => 'admin',
  1509. 'args' => array(
  1510. 'class' => 'Server',
  1511. 'output' => 'details',
  1512. 'separator' => ';',
  1513. 'reconciliationkeys' => '',
  1514. ),
  1515. '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",
  1516. ),
  1517. array(
  1518. 'desc' => 'Load NW if',
  1519. 'login' => 'admin',
  1520. 'password' => 'admin',
  1521. 'args' => array(
  1522. 'class' => 'NetworkInterface',
  1523. 'output' => 'details',
  1524. 'separator' => ';',
  1525. 'reconciliationkeys' => '',
  1526. ),
  1527. '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;;",
  1528. ),
  1529. // Data Bruno
  1530. array(
  1531. 'desc' => 'Load NW devices from real life',
  1532. 'login' => 'admin',
  1533. 'password' => 'admin',
  1534. 'args' => array(
  1535. 'class' => 'NetworkDevice',
  1536. 'output' => 'details',
  1537. 'separator' => ';',
  1538. 'reconciliationkeys' => 'org_id,Name',
  1539. ),
  1540. 'csvdata' => 'name;management_ip;importance;Owner organization->Name;type
  1541. truc-machin-bidule;172.15.255.150;high;My Company/Department;switch
  1542. 10.15.255.222;10.15.255.222;high;My Company/Department;switch',
  1543. ),
  1544. array(
  1545. 'desc' => 'Load NW ifs',
  1546. 'login' => 'admin',
  1547. 'password' => 'admin',
  1548. 'args' => array(
  1549. 'class' => 'NetworkInterface',
  1550. 'output' => 'details',
  1551. 'separator' => ';',
  1552. 'reconciliationkeys' => 'device_id->name,name',
  1553. ),
  1554. 'csvdata' => 'device_id->name;org_id->name;name;ip_address;ip_mask;speed;link_type;mac_address;physical_type
  1555. truc-machin-bidule;My Company/Department;"GigabitEthernet44";;;0;downlink;00 12 F2 CB C4 EB ;ethernet
  1556. truc-machin-bidule;My Company/Department;"GigabitEthernet38";;;0;downlink;00 12 F2 CB C4 E5 ;ethernet
  1557. un-autre;My Company/Department;"GigabitEthernet2/3";;;1000000000;uplink;00 12 F2 20 0F 1A ;ethernet',
  1558. ),
  1559. array(
  1560. 'desc' => 'The simplest data load',
  1561. 'login' => 'admin',
  1562. 'password' => 'admin',
  1563. 'args' => array(
  1564. 'class' => 'Location',
  1565. 'output' => 'details',
  1566. ),
  1567. 'csvdata' => "name\nParis",
  1568. ),
  1569. array(
  1570. 'desc' => 'The simplest data load + org',
  1571. 'login' => 'admin',
  1572. 'password' => 'admin',
  1573. 'args' => array(
  1574. 'class' => 'Location',
  1575. 'output' => 'details',
  1576. 'separator' => ';',
  1577. ),
  1578. 'csvdata' => "name;org_id\nParis;2",
  1579. ),
  1580. array(
  1581. 'desc' => 'The simplest data load + org (name)',
  1582. 'login' => 'admin',
  1583. 'password' => 'admin',
  1584. 'args' => array(
  1585. 'class' => 'Location',
  1586. 'output' => 'details',
  1587. 'separator' => ';',
  1588. ),
  1589. 'csvdata' => "name;org_name\nParis;Demo",
  1590. ),
  1591. array(
  1592. 'desc' => 'The simplest data load + org (code)',
  1593. 'login' => 'admin',
  1594. 'password' => 'admin',
  1595. 'args' => array(
  1596. 'class' => 'Location',
  1597. 'output' => 'details',
  1598. 'separator' => ';',
  1599. ),
  1600. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1601. ),
  1602. array(
  1603. 'desc' => 'Ouput: summary',
  1604. 'login' => 'admin',
  1605. 'password' => 'admin',
  1606. 'args' => array(
  1607. 'class' => 'Location',
  1608. 'output' => 'summary',
  1609. 'separator' => ';',
  1610. ),
  1611. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1612. ),
  1613. array(
  1614. 'desc' => 'Ouput: retcode',
  1615. 'login' => 'admin',
  1616. 'password' => 'admin',
  1617. 'args' => array(
  1618. 'class' => 'Location',
  1619. 'output' => 'retcode',
  1620. 'separator' => ';',
  1621. ),
  1622. 'csvdata' => "name;org_id->code\nParis;DEMO",
  1623. ),
  1624. array(
  1625. 'desc' => 'Error in reconciliation list',
  1626. 'login' => 'admin',
  1627. 'password' => 'admin',
  1628. 'args' => array(
  1629. 'class' => 'Location',
  1630. 'output' => 'details',
  1631. 'separator' => ';',
  1632. 'reconciliationkeys' => 'org_id',
  1633. ),
  1634. 'csvdata' => "org_name;name\nDemo;Paris",
  1635. ),
  1636. array(
  1637. 'desc' => 'Error in attribute list that does not allow to compute reconciliation scheme',
  1638. 'login' => 'admin',
  1639. 'password' => 'admin',
  1640. 'args' => array(
  1641. 'class' => 'Location',
  1642. 'output' => 'details',
  1643. 'separator' => ';',
  1644. ),
  1645. 'csvdata' => "org_name;country\nDemo;France",
  1646. ),
  1647. array(
  1648. 'desc' => 'Error in attribute list - case A',
  1649. 'login' => 'admin',
  1650. 'password' => 'admin',
  1651. 'args' => array(
  1652. 'class' => 'Location',
  1653. 'output' => 'details',
  1654. 'separator' => ';',
  1655. ),
  1656. 'csvdata' => "name;org\nParis;2",
  1657. ),
  1658. array(
  1659. 'desc' => 'Error in attribute list - case B1 (key->attcode)',
  1660. 'login' => 'admin',
  1661. 'password' => 'admin',
  1662. 'args' => array(
  1663. 'class' => 'Location',
  1664. 'output' => 'details',
  1665. 'separator' => ';',
  1666. ),
  1667. 'csvdata' => "name;org->code\nParis;DEMO",
  1668. ),
  1669. array(
  1670. 'desc' => 'Error in attribute list - case B2 (key->attcode)',
  1671. 'login' => 'admin',
  1672. 'password' => 'admin',
  1673. 'args' => array(
  1674. 'class' => 'Location',
  1675. 'output' => 'details',
  1676. 'separator' => ';',
  1677. ),
  1678. 'csvdata' => "name;org_id->duns\nParis;DEMO",
  1679. ),
  1680. array(
  1681. 'desc' => 'Always changing... special comment in change tracking',
  1682. 'login' => 'admin',
  1683. 'password' => 'admin',
  1684. 'args' => array(
  1685. 'class' => 'Location',
  1686. 'output' => 'details',
  1687. 'separator' => ';',
  1688. 'comment' => 'automated testing'
  1689. ),
  1690. 'csvdata' => "org_name;name;address\nDemo;Le pantheon;Addresse bidon:".((string)microtime(true)),
  1691. ),
  1692. array(
  1693. 'desc' => 'Always changing... but "simulate"',
  1694. 'login' => 'admin',
  1695. 'password' => 'admin',
  1696. 'args' => array(
  1697. 'class' => 'Location',
  1698. 'output' => 'details',
  1699. 'separator' => ';',
  1700. 'simulate' => '1',
  1701. 'comment' => 'SHOULD NEVER APPEAR IN THE HISTORY'
  1702. ),
  1703. 'csvdata' => "org_name;name;address\nDemo;Le pantheon;restore address?",
  1704. ),
  1705. array(
  1706. 'desc' => 'Load a user account',
  1707. 'login' => 'admin',
  1708. 'password' => 'admin',
  1709. 'args' => array(
  1710. 'class' => 'UserLocal',
  1711. 'output' => 'details',
  1712. 'separator' => ',',
  1713. 'simulate' => '0',
  1714. 'comment' => 'automated testing'
  1715. ),
  1716. 'csvdata' => "login,password,profile_list\nby_import_csv,fakepwd,profileid->name:Configuration Manager|profileid:10;reason:direct id",
  1717. ),
  1718. );
  1719. $sSubTests = utils::ReadParam('subtests', null, true, 'raw_data');
  1720. if (is_null($sSubTests))
  1721. {
  1722. foreach ($aLoads as $iTestId => $aLoadSpec)
  1723. {
  1724. $this->DoExecSingleLoad($aLoadSpec, $iTestId);
  1725. }
  1726. }
  1727. else
  1728. {
  1729. $aSubTests = explode(',', $sSubTests);
  1730. foreach ($aSubTests as $iTestId)
  1731. {
  1732. $this->DoExecSingleLoad($aLoads[$iTestId], $iTestId);
  1733. }
  1734. }
  1735. }
  1736. }
  1737. ///////////////////////////////////////////////////////////////////////////
  1738. // Test massive data load
  1739. ///////////////////////////////////////////////////////////////////////////
  1740. define('IMPORT_COUNT', 4000);
  1741. class TestImportRESTMassive extends TestImportREST
  1742. {
  1743. static public function GetName()
  1744. {
  1745. return 'CSV import (REST) - HUGE data set ('.IMPORT_COUNT.' PCs)';
  1746. }
  1747. static public function GetDescription()
  1748. {
  1749. return 'Stress import.php';
  1750. }
  1751. protected function DoExecute()
  1752. {
  1753. $aLoadSpec = array(
  1754. 'desc' => 'Loading PCs: '.IMPORT_COUNT,
  1755. 'args' => array(
  1756. 'class' => 'PC',
  1757. 'output' => 'summary',
  1758. ),
  1759. 'csvdata' => "name;org_id;brand\n",
  1760. );
  1761. for($i = 0 ; $i <= IMPORT_COUNT ; $i++)
  1762. {
  1763. $aLoadSpec['csvdata'] .= "pc.import.$i;2;Combodo\n";
  1764. }
  1765. $this->DoExecSingleLoad($aLoadSpec);
  1766. }
  1767. }
  1768. ///////////////////////////////////////////////////////////////////////////
  1769. // Test data exchange
  1770. ///////////////////////////////////////////////////////////////////////////
  1771. class TestDataExchange extends TestBizModel
  1772. {
  1773. static public function GetName()
  1774. {
  1775. return 'Data exchange';
  1776. }
  1777. static public function GetDescription()
  1778. {
  1779. return 'Test REST services: synchro_import and synchro_exec';
  1780. }
  1781. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  1782. protected function DoExecScenario($aSingleScenario)
  1783. {
  1784. echo "<div style=\"padding: 10;\">\n";
  1785. echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aSingleScenario['desc']}</h3>\n";
  1786. $sClass = $aSingleScenario['target_class'];
  1787. $aTargetData = $aSingleScenario['target_data'];
  1788. $aSourceData = $aSingleScenario['source_data'];
  1789. $aTargetAttributes = array_shift($aTargetData);
  1790. $aSourceAttributes = array_shift($aSourceData);
  1791. if (count($aSourceData) + 1 != count($aTargetData))
  1792. {
  1793. throw new Exception("Target data must contain exactly ".(count($aSourceData) + 1)." items, found ".count($aTargetData));
  1794. }
  1795. // Create the data source
  1796. //
  1797. $oDataSource = new SynchroDataSource();
  1798. $oDataSource->Set('name', 'Test data sync '.time());
  1799. $oDataSource->Set('description', 'unit test - created automatically');
  1800. $oDataSource->Set('status', 'production');
  1801. $oDataSource->Set('user_id', 0);
  1802. $oDataSource->Set('scope_class', $sClass);
  1803. $oDataSource->Set('scope_restriction', '');
  1804. $oDataSource->Set('full_load_periodicity', $aSingleScenario['full_load_periodicity']);
  1805. $oDataSource->Set('reconciliation_policy', $aSingleScenario['reconciliation_policy']);
  1806. $oDataSource->Set('action_on_zero', $aSingleScenario['action_on_zero']);
  1807. $oDataSource->Set('action_on_one', $aSingleScenario['action_on_one']);
  1808. $oDataSource->Set('action_on_multiple', $aSingleScenario['action_on_multiple']);
  1809. $oDataSource->Set('delete_policy', $aSingleScenario['delete_policy']);
  1810. $oDataSource->Set('delete_policy_update', $aSingleScenario['delete_policy_update']);
  1811. $oDataSource->Set('delete_policy_retention', $aSingleScenario['delete_policy_retention']);
  1812. $iDataSourceId = $this->ObjectToDB($oDataSource, true /* reload */);
  1813. $oAttributeSet = $oDataSource->Get('attribute_list');
  1814. while ($oAttribute = $oAttributeSet->Fetch())
  1815. {
  1816. if (array_key_exists($oAttribute->Get('attcode'), $aSingleScenario['attributes']))
  1817. {
  1818. $aAttribInfo = $aSingleScenario['attributes'][$oAttribute->Get('attcode')];
  1819. if (array_key_exists('reconciliation_attcode', $aAttribInfo))
  1820. {
  1821. $oAttribute->Set('reconciliation_attcode', $aAttribInfo['reconciliation_attcode']);
  1822. }
  1823. $oAttribute->Set('update', $aAttribInfo['do_update']);
  1824. $oAttribute->Set('reconcile', $aAttribInfo['do_reconcile']);
  1825. }
  1826. else
  1827. {
  1828. $oAttribute->Set('update', false);
  1829. $oAttribute->Set('reconcile', false);
  1830. }
  1831. $this->UpdateObjectInDB($oAttribute);
  1832. }
  1833. // Prepare list of prefixes -> make sure objects are unique with regard to the reconciliation scheme
  1834. $aPrefixes = array(); // attcode => prefix
  1835. foreach($aSourceAttributes as $iDummy => $sAttCode)
  1836. {
  1837. $aPrefixes[$sAttCode] = ''; // init with something
  1838. }
  1839. foreach($aSingleScenario['attributes'] as $sAttCode => $aAttribInfo)
  1840. {
  1841. if (isset($aAttribInfo['automatic_prefix']) && $aAttribInfo['automatic_prefix'])
  1842. {
  1843. $aPrefixes[$sAttCode] = 'TEST_'.$iDataSourceId.'_';
  1844. }
  1845. }
  1846. // List existing objects (to be ignored in the analysis
  1847. //
  1848. $oAllObjects = new DBObjectSet(new DBObjectSearch($sClass));
  1849. $aExisting = $oAllObjects->ToArray(true);
  1850. $sExistingIds = implode(', ', array_keys($aExisting));
  1851. // Create the initial object list
  1852. //
  1853. $aInitialTarget = $aTargetData[0];
  1854. foreach($aInitialTarget as $aObjFields)
  1855. {
  1856. $oNewTarget = MetaModel::NewObject($sClass);
  1857. foreach($aTargetAttributes as $iAtt => $sAttCode)
  1858. {
  1859. $oNewTarget->Set($sAttCode, $aPrefixes[$sAttCode].$aObjFields[$iAtt]);
  1860. }
  1861. $this->ObjectToDB($oNewTarget);
  1862. }
  1863. foreach($aTargetData as $iRow => $aExpectedObjects)
  1864. {
  1865. sleep(2);
  1866. // Check the status (while ignoring existing objects)
  1867. //
  1868. if (empty($sExistingIds))
  1869. {
  1870. $oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass"));
  1871. }
  1872. else
  1873. {
  1874. $oObjects = new DBObjectSet(DBObjectSearch::FromOQL("SELECT $sClass WHERE id NOT IN($sExistingIds)"));
  1875. }
  1876. $aFound = $oObjects->ToArray();
  1877. $aErrors_Unexpected = array();
  1878. foreach($aFound as $iObj => $oObj)
  1879. {
  1880. // Is this object in the expected objects list
  1881. $bFoundMatch = false;
  1882. foreach($aExpectedObjects as $iExp => $aValues)
  1883. {
  1884. $bDoesMatch = true;
  1885. foreach($aTargetAttributes as $iCol => $sAttCode)
  1886. {
  1887. if ($oObj->Get($sAttCode) != $aPrefixes[$sAttCode].$aValues[$iCol])
  1888. {
  1889. $bDoesMatch = false;
  1890. break;
  1891. }
  1892. }
  1893. if ($bDoesMatch)
  1894. {
  1895. $bFoundMatch = true;
  1896. unset($aExpectedObjects[$iExp]);
  1897. break;
  1898. }
  1899. }
  1900. if (!$bFoundMatch)
  1901. {
  1902. $aErrors_Unexpected[] = $oObj->GetKey();
  1903. }
  1904. }
  1905. // Display the current status
  1906. //
  1907. echo "<p>Status at step $iRow</p>\n";
  1908. $aCurrentDataSet = array();
  1909. foreach($aFound as $iObj => $oObj)
  1910. {
  1911. $aObjDesc = array(
  1912. 'Status' => (in_array($iObj, $aErrors_Unexpected) ? 'unexpected' : 'ok'),
  1913. 'Object' => $oObj->GetHyperLink()
  1914. );
  1915. foreach($aTargetAttributes as $iCol => $sAttCode)
  1916. {
  1917. $aObjDesc[$sAttCode] = $oObj->Get($sAttCode);
  1918. }
  1919. $aCurrentDataSet[] = $aObjDesc;
  1920. }
  1921. if (count($aExpectedObjects) > 0)
  1922. {
  1923. foreach($aExpectedObjects as $iExp => $aValues)
  1924. {
  1925. $aObjDesc = array(
  1926. 'Status' => 'missing',
  1927. 'Object' => 'n/a'
  1928. );
  1929. foreach($aTargetAttributes as $iCol => $sAttCode)
  1930. {
  1931. $aObjDesc[$sAttCode] = $aPrefixes[$sAttCode].$aValues[$iCol];
  1932. }
  1933. $aCurrentDataSet[] = $aObjDesc;
  1934. }
  1935. }
  1936. echo MyHelpers::make_table_from_assoc_array($aCurrentDataSet);
  1937. if ((count($aErrors_Unexpected) > 0) || (count($aExpectedObjects) > 0))
  1938. {
  1939. throw new UnitTestException("The current status in iTop does not match the expectations");
  1940. }
  1941. // If not on the final row, run a data exchange sequence
  1942. //
  1943. if (array_key_exists($iRow, $aSourceData))
  1944. {
  1945. $aToBeLoaded = $aSourceData[$iRow];
  1946. $sCsvData = implode(';', $aSourceAttributes)."\n";
  1947. foreach($aToBeLoaded as $aDataRow)
  1948. {
  1949. $aFinalData = array();
  1950. foreach($aDataRow as $iCol => $value)
  1951. {
  1952. if (is_null($value))
  1953. {
  1954. $aFinalData[] = '<NULL>';
  1955. }
  1956. else
  1957. {
  1958. $sAttCode = $aSourceAttributes[$iCol];
  1959. $aFinalData[] = $aPrefixes[$sAttCode].$value;
  1960. }
  1961. }
  1962. $sCsvData .= implode(';', $aFinalData)."\n";
  1963. }
  1964. $aPostData = array('csvdata' => $sCsvData);
  1965. $aImportArgs = array(
  1966. 'data_source_id' => $iDataSourceId,
  1967. 'separator' => ';',
  1968. 'simulate' => 0,
  1969. 'output' => 'details',
  1970. );
  1971. $aGetParams = array();
  1972. $aGetParamReport = array();
  1973. foreach($aImportArgs as $sArg => $sValue)
  1974. {
  1975. $aGetParams[] = $sArg.'='.urlencode($sValue);
  1976. $aGetParamReport[] = $sArg.'='.$sValue;
  1977. }
  1978. $sGetParams = implode('&', $aGetParams);
  1979. $sLogin = isset($aSingleScenario['login']) ? $aSingleScenario['login'] : 'admin';
  1980. $sPassword = isset($aSingleScenario['password']) ? $aSingleScenario['password'] : 'admin';
  1981. $sRes = self::DoPostRequestAuth('../synchro/synchro_import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
  1982. // Report the load results
  1983. //
  1984. if (strlen($sCsvData) > 5000)
  1985. {
  1986. $sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
  1987. }
  1988. else
  1989. {
  1990. $sCsvDataViewable = $sCsvData;
  1991. }
  1992. $sCsvDataViewable = htmlentities($sCsvDataViewable, ENT_QUOTES, 'UTF-8');
  1993. echo "<div style=\"\">\n";
  1994. echo " <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
  1995. echo "</div>\n";
  1996. echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
  1997. if (stripos($sRes, 'exception') !== false)
  1998. {
  1999. throw new UnitTestException('Encountered an Exception during the last import/synchro');
  2000. }
  2001. }
  2002. }
  2003. return;
  2004. echo "</div>\n";
  2005. }
  2006. protected function DoExecute()
  2007. {
  2008. /*
  2009. $aScenarios = array(
  2010. array(
  2011. 'desc' => 'Load user logins',
  2012. 'login' => 'admin',
  2013. 'password' => 'admin',
  2014. 'target_class' => 'UserLocal',
  2015. 'full_load_periodicity' => 3600, // should be ignored in this case
  2016. 'reconciliation_policy' => 'use_attributes',
  2017. 'action_on_zero' => 'create',
  2018. 'action_on_one' => 'update',
  2019. 'action_on_multiple' => 'error',
  2020. 'delete_policy' => 'delete',
  2021. 'delete_policy_update' => '',
  2022. 'delete_policy_retention' => 0,
  2023. 'source_data' => array(
  2024. array('primary_key', 'login', 'password', 'profile_list'),
  2025. array(
  2026. array('user_A', 'login_A', 'password_A', 'profileid:10;reason:he/she is managing services'),
  2027. ),
  2028. ),
  2029. 'target_data' => array(
  2030. array('login'),
  2031. array(
  2032. // Initial state
  2033. ),
  2034. array(
  2035. array('login_A'),
  2036. ),
  2037. ),
  2038. 'attributes' => array(
  2039. 'login' => array(
  2040. 'do_reconcile' => true,
  2041. 'do_update' => true,
  2042. 'automatic_prefix' => true, // unique id (for unit testing)
  2043. ),
  2044. 'password' => array(
  2045. 'do_reconcile' => false,
  2046. 'do_update' => true,
  2047. ),
  2048. 'profile_list' => array(
  2049. 'do_reconcile' => false,
  2050. 'do_update' => true,
  2051. ),
  2052. ),
  2053. ),
  2054. );
  2055. */
  2056. $aScenarios = array(
  2057. array(
  2058. 'desc' => 'Simple scenario with delete option (and extkey given as org/name)',
  2059. 'login' => 'admin',
  2060. 'password' => 'admin',
  2061. 'target_class' => 'ApplicationSolution',
  2062. 'full_load_periodicity' => 3600, // should be ignored in this case
  2063. 'reconciliation_policy' => 'use_attributes',
  2064. 'action_on_zero' => 'create',
  2065. 'action_on_one' => 'update',
  2066. 'action_on_multiple' => 'error',
  2067. 'delete_policy' => 'delete',
  2068. 'delete_policy_update' => '',
  2069. 'delete_policy_retention' => 0,
  2070. 'source_data' => array(
  2071. array('primary_key', 'org_id', 'name', 'status'),
  2072. array(
  2073. array('obj_A', null, 'obj_A', 'production'), // org_id unchanged
  2074. array('obj_B', '_DUMMY_', 'obj_B', 'production'), // error, '_DUMMY_' unknown
  2075. array('obj_C', 'SOMECODE', 'obj_C', 'production'),
  2076. array('obj_D', null, 'obj_D', 'production'),
  2077. array('obj_E', '_DUMMY_', 'obj_E', 'production'),
  2078. ),
  2079. array(
  2080. ),
  2081. array(
  2082. ),
  2083. ),
  2084. 'target_data' => array(
  2085. array('org_id', 'name', 'status'),
  2086. array(
  2087. // Initial state
  2088. array(2, 'obj_A', 'production'),
  2089. array(2, 'obj_B', 'production'),
  2090. ),
  2091. array(
  2092. array(2, 'obj_A', 'production'),
  2093. array(2, 'obj_B', 'production'),
  2094. array(1, 'obj_C', 'production'),
  2095. ),
  2096. array(
  2097. array(2, 'obj_A', 'production'),
  2098. array(2, 'obj_B', 'production'),
  2099. // deleted !
  2100. ),
  2101. // The only diff here is into the log
  2102. array(
  2103. array(2, 'obj_A', 'production'),
  2104. array(2, 'obj_B', 'production'),
  2105. // deleted !
  2106. ),
  2107. ),
  2108. 'attributes' => array(
  2109. 'org_id' => array(
  2110. 'do_reconcile' => false,
  2111. 'do_update' => true,
  2112. 'reconciliation_attcode' => 'code',
  2113. ),
  2114. 'name' => array(
  2115. 'do_reconcile' => true,
  2116. 'do_update' => true,
  2117. 'automatic_prefix' => true, // unique id
  2118. ),
  2119. 'status' => array(
  2120. 'do_reconcile' => false,
  2121. 'do_update' => true,
  2122. ),
  2123. ),
  2124. ),
  2125. // );
  2126. // $aXXXXScenarios = array(
  2127. array(
  2128. 'desc' => 'Update then delete with retention (to complete with manual testing) and reconciliation on org/name',
  2129. 'login' => 'admin',
  2130. 'password' => 'admin',
  2131. 'target_class' => 'ApplicationSolution',
  2132. 'full_load_periodicity' => 3600,
  2133. 'reconciliation_policy' => 'use_attributes',
  2134. 'action_on_zero' => 'create',
  2135. 'action_on_one' => 'update',
  2136. 'action_on_multiple' => 'error',
  2137. 'delete_policy' => 'update_then_delete',
  2138. 'delete_policy_update' => 'status:obsolete',
  2139. 'delete_policy_retention' => 15,
  2140. 'source_data' => array(
  2141. array('primary_key', 'org_id', 'name', 'status'),
  2142. array(
  2143. array('obj_A', 'Demo', 'obj_A', 'production'),
  2144. ),
  2145. array(
  2146. ),
  2147. ),
  2148. 'target_data' => array(
  2149. array('org_id', 'name', 'status'),
  2150. array(
  2151. // Initial state
  2152. ),
  2153. array(
  2154. array(2, 'obj_A', 'production'),
  2155. ),
  2156. array(
  2157. array(2, 'obj_A', 'obsolete'),
  2158. // deleted !
  2159. ),
  2160. ),
  2161. 'attributes' => array(
  2162. 'org_id' => array(
  2163. 'do_reconcile' => true,
  2164. 'do_update' => true,
  2165. 'reconciliation_attcode' => 'name',
  2166. ),
  2167. 'name' => array(
  2168. 'do_reconcile' => true,
  2169. 'do_update' => true,
  2170. 'automatic_prefix' => true, // unique id
  2171. ),
  2172. 'status' => array(
  2173. 'do_reconcile' => false,
  2174. 'do_update' => true,
  2175. ),
  2176. ),
  2177. ),
  2178. //);
  2179. //$aXXScenarios = array(
  2180. array(
  2181. 'desc' => 'Simple scenario loading a few ApplicationSolution',
  2182. 'login' => 'admin',
  2183. 'password' => 'admin',
  2184. 'target_class' => 'ApplicationSolution',
  2185. 'full_load_periodicity' => 3600,
  2186. 'reconciliation_policy' => 'use_attributes',
  2187. 'action_on_zero' => 'create',
  2188. 'action_on_one' => 'update',
  2189. 'action_on_multiple' => 'error',
  2190. 'delete_policy' => 'update',
  2191. 'delete_policy_update' => 'status:obsolete',
  2192. 'delete_policy_retention' => 0,
  2193. 'source_data' => array(
  2194. array('primary_key', 'org_id', 'name', 'status'),
  2195. array(
  2196. array('obj_A', 2, 'obj_A', 'production'),
  2197. array('obj_B', 2, 'obj_B', 'implementation'),
  2198. array('obj_C', 2, 'obj_C', 'implementation'),
  2199. ),
  2200. array(
  2201. array('obj_A', 2, 'obj_A', 'production'),
  2202. array('obj_B', 2, 'obj_B', 'implementation'),
  2203. array('obj_C', 2, 'obj_C', 'implementation'),
  2204. ),
  2205. array(
  2206. array('obj_A', 2, 'obj_A', 'production'),
  2207. array('obj_C', 2, 'obj_C', 'implementation'),
  2208. array('obj_D', 2, 'obj_D', 'implementation'),
  2209. ),
  2210. array(
  2211. array('obj_C', 2, 'obj_C', 'production'),
  2212. ),
  2213. array(
  2214. array('obj_C', 2, 'obj_C', 'production'),
  2215. ),
  2216. ),
  2217. 'target_data' => array(
  2218. array('org_id', 'name', 'status'),
  2219. array(
  2220. // Initial state
  2221. array(2, 'obj_A', 'implementation'),
  2222. array(2, 'obj_B', 'production'),
  2223. array(2, 'obj_B', 'implementation'),
  2224. ),
  2225. array(
  2226. array(2, 'obj_A', 'production'),
  2227. array(2, 'obj_B', 'production'),
  2228. array(2, 'obj_B', 'implementation'),
  2229. array(2, 'obj_C', 'implementation'),
  2230. ),
  2231. array(
  2232. array(2, 'obj_A', 'production'),
  2233. array(2, 'obj_B', 'production'),
  2234. array(2, 'obj_B', 'implementation'),
  2235. array(2, 'obj_C', 'implementation'),
  2236. ),
  2237. array(
  2238. array(2, 'obj_A', 'production'),
  2239. array(2, 'obj_B', 'production'),
  2240. array(2, 'obj_B', 'implementation'),
  2241. array(2, 'obj_C', 'implementation'),
  2242. array(2, 'obj_D', 'implementation'),
  2243. ),
  2244. array(
  2245. array(2, 'obj_A', 'obsolete'),
  2246. array(2, 'obj_B', 'production'),
  2247. array(2, 'obj_B', 'implementation'),
  2248. array(2, 'obj_C', 'production'),
  2249. array(2, 'obj_D', 'obsolete'),
  2250. ),
  2251. array(
  2252. array(2, 'obj_A', 'obsolete'),
  2253. array(2, 'obj_B', 'production'),
  2254. array(2, 'obj_B', 'implementation'),
  2255. array(2, 'obj_C', 'production'),
  2256. array(2, 'obj_D', 'obsolete'),
  2257. ),
  2258. ),
  2259. 'attributes' => array(
  2260. 'org_id' => array(
  2261. 'do_reconcile' => false,
  2262. 'do_update' => true,
  2263. ),
  2264. 'name' => array(
  2265. 'do_reconcile' => true,
  2266. 'do_update' => true,
  2267. 'automatic_prefix' => true, // unique id
  2268. ),
  2269. 'status' => array(
  2270. 'do_reconcile' => false,
  2271. 'do_update' => true,
  2272. ),
  2273. ),
  2274. ),
  2275. );
  2276. foreach ($aScenarios as $aSingleScenario)
  2277. {
  2278. $this->DoExecScenario($aSingleScenario);
  2279. }
  2280. }
  2281. }
  2282. ///////////////////////////////////////////////////////////////////////////
  2283. // Test SOAP services
  2284. ///////////////////////////////////////////////////////////////////////////
  2285. $aCreateTicketSpecs = array(
  2286. array(
  2287. 'service_category' => 'BasicServices',
  2288. 'verb' => 'GetVersion',
  2289. // 'expected result' => '1.0.1',
  2290. 'expected result' => '$ITOP_VERSION$ [dev]',
  2291. 'explain result' => 'no comment!',
  2292. 'args' => array(),
  2293. ),
  2294. array(
  2295. 'service_category' => '',
  2296. 'verb' => 'CreateIncidentTicket',
  2297. 'expected result' => true,
  2298. 'explain result' => 'link attribute unknown + a CI not found',
  2299. 'args' => array(
  2300. 'admin', /* sLogin */
  2301. 'admin', /* sPassword */
  2302. 'desc of ticket', /* sDescription */
  2303. 'initial situation blah blah blah', /* sInitialSituation */
  2304. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2305. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2306. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Telecom and connectivity'))), /* aServiceDesc */
  2307. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Network Troubleshooting'))), /* aServiceSubcategoryDesc */
  2308. 'sub product of the service', /* sProduct */
  2309. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2310. array(
  2311. new SOAPLinkCreationSpec(
  2312. 'InfrastructureCI',
  2313. array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
  2314. array(new SOAPAttributeValue('impacting', 'very critical'))
  2315. ),
  2316. new SOAPLinkCreationSpec(
  2317. 'NetworkDevice',
  2318. array(new SOAPSearchCondition('name', 'switch01')),
  2319. array(new SOAPAttributeValue('impact', 'who cares'))
  2320. ),
  2321. new SOAPLinkCreationSpec(
  2322. 'Server',
  2323. array(new SOAPSearchCondition('name', 'thisone')),
  2324. array(new SOAPAttributeValue('impact', 'our lives'))
  2325. ),
  2326. ), /* aImpact */
  2327. '1', /* sImpact */
  2328. '1', /* sUrgency */
  2329. ),
  2330. ),
  2331. array(
  2332. 'service_category' => '',
  2333. 'verb' => 'CreateIncidentTicket',
  2334. 'expected result' => true,
  2335. 'explain result' => 'caller not specified',
  2336. 'args' => array(
  2337. 'admin', /* sLogin */
  2338. 'admin', /* sPassword */
  2339. 'PC burning', /* sDescription */
  2340. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2341. new SOAPExternalKeySearch(), /* aCallerDesc */
  2342. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2343. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2344. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2345. 'sub product of the service', /* sProduct */
  2346. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2347. array(
  2348. new SOAPLinkCreationSpec(
  2349. 'InfrastructureCI',
  2350. array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
  2351. array()
  2352. ), /* aImpact */
  2353. ),
  2354. '1', /* sImpact */
  2355. '1', /* sUrgency */
  2356. ),
  2357. ),
  2358. array(
  2359. 'service_category' => '',
  2360. 'verb' => 'CreateIncidentTicket',
  2361. 'expected result' => false,
  2362. 'explain result' => 'wrong class on CI to attach',
  2363. 'args' => array(
  2364. 'admin', /* sLogin */
  2365. 'admin', /* sPassword */
  2366. 'PC burning', /* sDescription */
  2367. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2368. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2369. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2370. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2371. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2372. 'sub product of the service', /* sProduct */
  2373. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2374. array(
  2375. new SOAPLinkCreationSpec(
  2376. 'logInfra',
  2377. array(new SOAPSearchCondition('dummyfiltercode', 2)),
  2378. array(new SOAPAttributeValue('impact', 'very critical'))
  2379. ),
  2380. ), /* aImpact */
  2381. '1', /* sImpact */
  2382. '1', /* sUrgency */
  2383. ),
  2384. ),
  2385. array(
  2386. 'service_category' => '',
  2387. 'verb' => 'CreateIncidentTicket',
  2388. 'expected result' => false,
  2389. 'explain result' => 'wrong search condition on CI to attach',
  2390. 'args' => array(
  2391. 'admin', /* sLogin */
  2392. 'admin', /* sPassword */
  2393. 'PC burning', /* sDescription */
  2394. 'The power supply suddenly started to warm up', /* sInitialSituation */
  2395. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2396. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2397. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2398. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2399. 'sub product of the service', /* sProduct */
  2400. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2401. array(
  2402. new SOAPLinkCreationSpec(
  2403. 'InfrastructureCI',
  2404. array(new SOAPSearchCondition('dummyfiltercode', 2)),
  2405. array(new SOAPAttributeValue('impact', 'very critical'))
  2406. ),
  2407. ), /* aImpact */
  2408. '1', /* sImpact */
  2409. '1', /* sUrgency */
  2410. ),
  2411. ),
  2412. array(
  2413. 'service_category' => '',
  2414. 'verb' => 'CreateIncidentTicket',
  2415. 'expected result' => true,
  2416. 'explain result' => 'no CI to attach (empty array)',
  2417. 'args' => array(
  2418. 'admin', /* sLogin */
  2419. 'admin', /* sPassword */
  2420. 'Houston not reachable', /* sDescription */
  2421. 'Tried to join the shuttle', /* sInitialSituation */
  2422. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2423. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2424. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2425. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2426. 'sub product of the service', /* sProduct */
  2427. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2428. array(
  2429. ), /* aImpact */
  2430. '1', /* sImpact */
  2431. '1', /* sUrgency */
  2432. ),
  2433. ),
  2434. array(
  2435. 'service_category' => '',
  2436. 'verb' => 'CreateIncidentTicket',
  2437. 'expected result' => true,
  2438. 'explain result' => 'no CI to attach (null)',
  2439. 'args' => array(
  2440. 'admin', /* sLogin */
  2441. 'admin', /* sPassword */
  2442. 'Houston not reachable', /* sDescription */
  2443. 'Tried to join the shuttle', /* sInitialSituation */
  2444. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2445. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2446. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2447. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2448. 'sub product of the service', /* sProduct */
  2449. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2450. null, /* aImpact */
  2451. '1', /* sImpact */
  2452. '1', /* sUrgency */
  2453. ),
  2454. ),
  2455. array(
  2456. 'service_category' => '',
  2457. 'verb' => 'CreateIncidentTicket',
  2458. 'expected result' => true,
  2459. 'explain result' => 'caller unknown',
  2460. 'args' => array(
  2461. 'admin', /* sLogin */
  2462. 'admin', /* sPassword */
  2463. 'Houston not reachable', /* sDescription */
  2464. 'Tried to join the shuttle', /* sInitialSituation */
  2465. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1000))), /* aCallerDesc */
  2466. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2467. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2468. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2469. 'sub product of the service', /* sProduct */
  2470. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2471. array(
  2472. ), /* aImpact */
  2473. '1', /* sImpact */
  2474. '1', /* sUrgency */
  2475. ),
  2476. ),
  2477. array(
  2478. 'service_category' => '',
  2479. 'verb' => 'CreateIncidentTicket',
  2480. 'expected result' => false,
  2481. 'explain result' => 'wrong values for impact and urgency',
  2482. 'args' => array(
  2483. 'admin', /* sLogin */
  2484. 'admin', /* sPassword */
  2485. 'Houston not reachable', /* sDescription */
  2486. 'Tried to join the shuttle', /* sInitialSituation */
  2487. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2488. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2489. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2490. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2491. 'sub product of the service', /* sProduct */
  2492. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2493. array(
  2494. ), /* aImpact */
  2495. '6', /* sImpact */
  2496. '7', /* sUrgency */
  2497. ),
  2498. ),
  2499. array(
  2500. 'service_category' => '',
  2501. 'verb' => 'CreateIncidentTicket',
  2502. 'expected result' => false,
  2503. 'explain result' => 'wrong password',
  2504. 'args' => array(
  2505. 'admin', /* sLogin */
  2506. 'xxxxx', /* sPassword */
  2507. 'Houston not reachable', /* sDescription */
  2508. 'Tried to join the shuttle', /* sInitialSituation */
  2509. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2510. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2511. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2512. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2513. 'sub product of the service', /* sProduct */
  2514. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2515. array(
  2516. ), /* aImpact */
  2517. '1', /* sImpact */
  2518. '1', /* sUrgency */
  2519. ),
  2520. ),
  2521. array(
  2522. 'service_category' => '',
  2523. 'verb' => 'CreateIncidentTicket',
  2524. 'expected result' => false,
  2525. 'explain result' => 'wrong login',
  2526. 'args' => array(
  2527. 'xxxxx', /* sLogin */
  2528. 'yyyyy', /* sPassword */
  2529. 'Houston not reachable', /* sDescription */
  2530. 'Tried to join the shuttle', /* sInitialSituation */
  2531. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
  2532. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
  2533. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Computers and peripherals'))), /* aServiceDesc */
  2534. new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
  2535. 'sub product of the service', /* sProduct */
  2536. new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
  2537. array(
  2538. ), /* aImpact */
  2539. '1', /* sImpact */
  2540. '1', /* sUrgency */
  2541. ),
  2542. ),
  2543. array(
  2544. 'service_category' => '',
  2545. 'verb' => 'SearchObjects',
  2546. 'expected result' => true,
  2547. 'explain result' => '',
  2548. 'args' => array(
  2549. 'admin', /* sLogin */
  2550. 'admin', /* sPassword */
  2551. 'SELECT Incident WHERE id > 20', /* sOQL */
  2552. ),
  2553. ),
  2554. array(
  2555. 'service_category' => '',
  2556. 'verb' => 'SearchObjects',
  2557. 'expected result' => false,
  2558. 'explain result' => 'wrong OQL',
  2559. 'args' => array(
  2560. 'admin', /* sLogin */
  2561. 'admin', /* sPassword */
  2562. 'SELECT ThisClassDoesNotExist', /* sOQL */
  2563. ),
  2564. ),
  2565. );
  2566. $aManageCloudUsersSpecs = array(
  2567. array(
  2568. 'service_category' => '',
  2569. 'verb' => 'SearchObjects',
  2570. 'expected result' => false,
  2571. 'explain result' => 'wrong OQL',
  2572. 'args' => array(
  2573. 'admin', /* sLogin */
  2574. 'admin', /* sPassword */
  2575. 'SELECT ThisClassDoesNotExist', /* sOQL */
  2576. ),
  2577. ),
  2578. array(
  2579. 'service_category' => '',
  2580. 'verb' => 'SearchObjects',
  2581. 'expected result' => true,
  2582. 'explain result' => 'ok',
  2583. 'args' => array(
  2584. 'admin', /* sLogin */
  2585. 'admin', /* sPassword */
  2586. 'SELECT Organization', /* sOQL */
  2587. ),
  2588. ),
  2589. array(
  2590. 'service_category' => 'CloudUsersManagementService',
  2591. 'verb' => 'CreateAccount',
  2592. 'expected result' => true,
  2593. 'explain result' => 'ok',
  2594. 'args' => array(
  2595. 'admin', /* sAdminLogin */
  2596. 'admin', /* sAdminPassword */
  2597. 'http://myserver.mydomain.fr:8080', /* sCloudMgrUrl */
  2598. 'andros@combodo.com', /* sLogin */
  2599. 'André', /* sFirstName */
  2600. 'Dupont', /* sLastName */
  2601. 1, /* iOrgId */
  2602. 'FR FR', /* sLanguage */
  2603. array(
  2604. array(
  2605. new SOAPKeyValue('profile_id', '2'),
  2606. new SOAPKeyValue('reason', 'whynot'),
  2607. ),
  2608. array(
  2609. new SOAPKeyValue('profile_id', '3'),
  2610. new SOAPKeyValue('reason', 'because'),
  2611. ),
  2612. ), /* aProfiles (array of key/value pairs) */
  2613. array(
  2614. ), /* aAllowedOrgs (array of key/value pairs) */
  2615. 'comment on the creation operation', /* sComment */
  2616. ),
  2617. ),
  2618. array(
  2619. 'service_category' => 'CloudUsersManagementService',
  2620. 'verb' => 'ModifyAccount',
  2621. 'expected result' => true,
  2622. 'explain result' => 'ok',
  2623. 'args' => array(
  2624. 'admin', /* sAdminLogin */
  2625. 'admin', /* sAdminPassword */
  2626. 'andros@combodo.com', /* sLogin */
  2627. 'nono', /* sFirstName */
  2628. 'robot', /* sLastName */
  2629. 2, /* iOrgId */
  2630. 'EN US', /* sLanguage */
  2631. array(
  2632. array(
  2633. new SOAPKeyValue('profile_id', '3'),
  2634. new SOAPKeyValue('reason', 'because'),
  2635. ),
  2636. ), /* aProfiles (array of key/value pairs) */
  2637. array(
  2638. ), /* aAllowedOrgs (array of key/value pairs) */
  2639. 'comment on the modify operation', /* sComment */
  2640. ),
  2641. ),
  2642. array(
  2643. 'service_category' => 'CloudUsersManagementService',
  2644. 'verb' => 'DeleteAccount',
  2645. 'expected result' => true,
  2646. 'explain result' => '',
  2647. 'args' => array(
  2648. 'admin', /* sAdminLogin */
  2649. 'admin', /* sAdminPassword */
  2650. 'andros@combodo.com', /* sLogin */
  2651. 'comment on the deletion operation', /* sComment */
  2652. ),
  2653. ),
  2654. array(
  2655. 'service_category' => 'CloudUsersManagementService',
  2656. 'verb' => 'DeleteAccount',
  2657. 'expected result' => false,
  2658. 'explain result' => 'wrong login',
  2659. 'args' => array(
  2660. 'admin', /* sAdminLogin */
  2661. 'admin', /* sAdminPassword */
  2662. 'taratatata@sdf.com', /* sLogin */
  2663. 'comment on the deletion operation', /* sComment */
  2664. ),
  2665. ),
  2666. );
  2667. abstract class TestSoap extends TestSoapWebService
  2668. {
  2669. static public function GetName() {return 'Test SOAP';}
  2670. static public function GetDescription() {return 'Do basic stuff to test the SOAP capability';}
  2671. protected $m_aTestSpecs;
  2672. protected function DoExecute()
  2673. {
  2674. 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";
  2675. $aSOAPMapping = SOAPMapping::GetMapping();
  2676. // this file is generated dynamically with location = here
  2677. $sWsdlUri = 'http'.(utils::IsConnectionSecure() ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../webservices/itop.wsdl.php';
  2678. ini_set("soap.wsdl_cache_enabled","0");
  2679. foreach ($this->m_aTestSpecs as $iPos => $aWebService)
  2680. {
  2681. echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
  2682. echo "<p>Using WSDL: $sWsdlUriForService</p>\n";
  2683. echo "<p>{$aWebService['explain result']}</p>\n";
  2684. $sWsdlUriForService = $sWsdlUri.'?service_category='.$aWebService['service_category'];
  2685. $this->m_SoapClient = new SoapClient
  2686. (
  2687. $sWsdlUriForService,
  2688. array(
  2689. 'classmap' => $aSOAPMapping,
  2690. 'trace' => 1,
  2691. )
  2692. );
  2693. if (false)
  2694. {
  2695. self::DumpVariable($this->m_SoapClient->__getTypes());
  2696. }
  2697. try
  2698. {
  2699. $oRes = call_user_func_array(array($this->m_SoapClient, $aWebService['verb']), $aWebService['args']);
  2700. }
  2701. catch(SoapFault $e)
  2702. {
  2703. print "<pre>\n";
  2704. print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n";
  2705. print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n";
  2706. print "</pre>";
  2707. print "Response in HTML: <p>".$this->m_SoapClient->__getLastResponse()."</p>";
  2708. throw $e;
  2709. }
  2710. self::DumpVariable($oRes);
  2711. print "<pre>\n";
  2712. print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n";
  2713. print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n";
  2714. print "</pre>";
  2715. if ($oRes instanceof SOAPResult)
  2716. {
  2717. $res = $oRes->status;
  2718. }
  2719. elseif ($oRes instanceof SOAPSimpleResult)
  2720. {
  2721. $res = $oRes->status;
  2722. }
  2723. else
  2724. {
  2725. $res = $oRes;
  2726. }
  2727. if ($res != $aWebService['expected result'])
  2728. {
  2729. echo "Expecting:<br/>\n";
  2730. var_dump($aWebService['expected result']);
  2731. echo "Obtained:<br/>\n";
  2732. var_dump($res);
  2733. throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  2734. }
  2735. }
  2736. }
  2737. }
  2738. abstract class TestSoapDirect extends TestBizModel
  2739. {
  2740. static public function GetName() {return 'Test web services locally';}
  2741. static public function GetDescription() {return 'Invoke the service directly (troubleshooting)';}
  2742. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  2743. protected $m_aTestSpecs;
  2744. protected function DoExecute()
  2745. {
  2746. foreach ($this->m_aTestSpecs as $iPos => $aWebService)
  2747. {
  2748. $sServiceClass = $aWebService['service_category'];
  2749. if (empty($sServiceClass)) $sServiceClass = 'BasicServices';
  2750. $oWebServices = new $sServiceClass();
  2751. echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
  2752. echo "<p>{$aWebService['explain result']}</p>\n";
  2753. $oRes = call_user_func_array(array($oWebServices, $aWebService['verb']), $aWebService['args']);
  2754. self::DumpVariable($oRes);
  2755. if ($oRes instanceof SOAPResult)
  2756. {
  2757. $res = $oRes->status;
  2758. }
  2759. elseif ($oRes instanceof SOAPSimpleResult)
  2760. {
  2761. $res = $oRes->status;
  2762. }
  2763. else
  2764. {
  2765. $res = $oRes;
  2766. }
  2767. if ($res != $aWebService['expected result'])
  2768. {
  2769. echo "Expecting:<br/>\n";
  2770. var_dump($aWebService['expected result']);
  2771. echo "Obtained:<br/>\n";
  2772. var_dump($res);
  2773. throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
  2774. }
  2775. }
  2776. return true;
  2777. }
  2778. }
  2779. class TestSoap_Tickets extends TestSoap
  2780. {
  2781. static public function GetName() {return 'Test SOAP - create ticket';}
  2782. protected function DoExecute()
  2783. {
  2784. global $aCreateTicketSpecs;
  2785. $this->m_aTestSpecs = $aCreateTicketSpecs;
  2786. return parent::DoExecute();
  2787. }
  2788. }
  2789. class TestSoapDirect_Tickets extends TestSoapDirect
  2790. {
  2791. static public function GetName() {return 'Test SOAP without SOAP - create ticket';}
  2792. protected function DoExecute()
  2793. {
  2794. global $aCreateTicketSpecs;
  2795. $this->m_aTestSpecs = $aCreateTicketSpecs;
  2796. return parent::DoExecute();
  2797. }
  2798. }
  2799. class TestSoap_ManageCloudUsers extends TestSoap
  2800. {
  2801. static public function GetName() {return 'Test SOAP - manage Cloud Users';}
  2802. protected function DoExecute()
  2803. {
  2804. global $aManageCloudUsersSpecs;
  2805. $this->m_aTestSpecs = $aManageCloudUsersSpecs;
  2806. return parent::DoExecute();
  2807. }
  2808. }
  2809. class TestSoapDirect_ManageCloudUsers extends TestSoapDirect
  2810. {
  2811. static public function GetName() {return 'Test SOAP without SOAP - manage Cloud Users';}
  2812. protected function DoExecute()
  2813. {
  2814. global $aManageCloudUsersSpecs;
  2815. $this->m_aTestSpecs = $aManageCloudUsersSpecs;
  2816. return parent::DoExecute();
  2817. }
  2818. }
  2819. ////////////////////// End of SOAP TESTS
  2820. class TestTriggerAndEmail extends TestBizModel
  2821. {
  2822. static public function GetName() {return 'Test trigger and email';}
  2823. static public function GetDescription() {return 'Create a trigger and an email, then activates the trigger';}
  2824. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  2825. protected function CreateEmailSpec($oTrigger, $sStatus, $sTo, $sCC, $sTesterEmail)
  2826. {
  2827. $oAction = MetaModel::NewObject("ActionEmail");
  2828. $oAction->Set("status", $sStatus);
  2829. $oAction->Set("name", "New server");
  2830. $oAction->Set("test_recipient", $sTesterEmail);
  2831. $oAction->Set("from", $sTesterEmail);
  2832. $oAction->Set("reply_to", $sTesterEmail);
  2833. $oAction->Set("to", $sTo);
  2834. $oAction->Set("cc", $sCC);
  2835. $oAction->Set("bcc", "");
  2836. $oAction->Set("subject", "New server: '\$this->name()$'");
  2837. $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>");
  2838. $oAction->Set("importance", "low");
  2839. $iActionId = $this->ObjectToDB($oAction, true);
  2840. $oLink = MetaModel::NewObject("lnkTriggerAction");
  2841. $oLink->Set("trigger_id", $oTrigger->GetKey());
  2842. $oLink->Set("action_id", $iActionId);
  2843. $oLink->Set("order", "1");
  2844. $iLink = $this->ObjectToDB($oLink, true);
  2845. }
  2846. protected function DoExecute()
  2847. {
  2848. $oMyPerson = MetaModel::NewObject("Person");
  2849. $oMyPerson->Set("name", "testemail1");
  2850. $oMyPerson->Set("first_name", "theodore");
  2851. $oMyPerson->Set("org_id", "1");
  2852. $oMyPerson->Set("email", "romain.quetiez@combodo.com");
  2853. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  2854. $oMyPerson = MetaModel::NewObject("Person");
  2855. $oMyPerson->Set("name", "testemail2");
  2856. $oMyPerson->Set("first_name", "theodore");
  2857. $oMyPerson->Set("org_id", "1");
  2858. $oMyPerson->Set("email", "denis.flaven@combodo.com");
  2859. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  2860. $oMyPerson = MetaModel::NewObject("Person");
  2861. $oMyPerson->Set("name", "testemail3");
  2862. $oMyPerson->Set("first_name", "theodore");
  2863. $oMyPerson->Set("org_id", "1");
  2864. $oMyPerson->Set("email", "erwan.taloc@combodo.com");
  2865. $iPersonId = $this->ObjectToDB($oMyPerson, true);
  2866. $oMyServer = MetaModel::NewObject("Server");
  2867. $oMyServer->Set("name", "wfr.terminator.com");
  2868. $oMyServer->Set("status", "production");
  2869. $oMyServer->Set("org_id", 2);
  2870. $iServerId = $this->ObjectToDB($oMyServer, true);
  2871. $oMyTrigger = MetaModel::NewObject("TriggerOnStateEnter");
  2872. $oMyTrigger->Set("description", "Testor");
  2873. $oMyTrigger->Set("target_class", "Server");
  2874. $oMyTrigger->Set("state", "Shipped");
  2875. $iTriggerId = $this->ObjectToDB($oMyTrigger, true);
  2876. // Error in OQL field(s)
  2877. //
  2878. $this->CreateEmailSpec
  2879. (
  2880. $oMyTrigger,
  2881. 'test',
  2882. "SELECT Person WHERE naime = 'Dali'",
  2883. "SELECT Server",
  2884. 'romain.quetiez@combodo.com'
  2885. );
  2886. // Error: no recipient
  2887. //
  2888. $this->CreateEmailSpec
  2889. (
  2890. $oMyTrigger,
  2891. 'test',
  2892. "",
  2893. "",
  2894. 'romain.quetiez@combodo.com'
  2895. );
  2896. // Test
  2897. //
  2898. $this->CreateEmailSpec
  2899. (
  2900. $oMyTrigger,
  2901. 'test',
  2902. "SELECT Person WHERE name LIKE 'testemail%'",
  2903. "SELECT Person",
  2904. 'romain.quetiez@combodo.com'
  2905. );
  2906. // Test failing because of a wrong test recipient address
  2907. //
  2908. $this->CreateEmailSpec
  2909. (
  2910. $oMyTrigger,
  2911. 'test',
  2912. "SELECT Person WHERE name LIKE 'testemail%'",
  2913. "",
  2914. 'toto@walibi.bg'
  2915. );
  2916. // Normal behavior
  2917. //
  2918. $this->CreateEmailSpec
  2919. (
  2920. $oMyTrigger,
  2921. 'enabled',
  2922. "SELECT Person WHERE name LIKE 'testemail%'",
  2923. "",
  2924. 'romain.quetiez@combodo.com'
  2925. );
  2926. // Does nothing, because it is disabled
  2927. //
  2928. $this->CreateEmailSpec
  2929. (
  2930. $oMyTrigger,
  2931. 'disabled',
  2932. "SELECT Person WHERE name = 'testemail%'",
  2933. "",
  2934. 'romain.quetiez@combodo.com'
  2935. );
  2936. $oMyTrigger->DoActivate($oMyServer->ToArgs('this'));
  2937. return true;
  2938. }
  2939. }
  2940. class TestDBProperties extends TestBizModel
  2941. {
  2942. static public function GetName()
  2943. {
  2944. return 'Itop - DB Properties';
  2945. }
  2946. static public function GetDescription()
  2947. {
  2948. return 'Write and read a dummy property';
  2949. }
  2950. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  2951. protected function DoExecute()
  2952. {
  2953. $sName = 'test';
  2954. DBProperty::SetProperty($sName, 'unix time:'.time(), 'means nothing', 'done with the automated test utility');
  2955. $sValue = DBProperty::GetProperty($sName, 'defaults to this because the table has not been created (1.0.1 install?)');
  2956. echo "<p>Write... then read property <b>$sName</b>, found: '$sValue'</p>\n";
  2957. }
  2958. }
  2959. class TestCreateObjects extends TestBizModel
  2960. {
  2961. static public function GetName()
  2962. {
  2963. return 'Itop - create objects';
  2964. }
  2965. static public function GetDescription()
  2966. {
  2967. return 'Create weird objects (reproduce a bug?)';
  2968. }
  2969. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  2970. protected function DoExecute()
  2971. {
  2972. $oMyObj = MetaModel::NewObject("Server");
  2973. $oMyObj->Set("name", "test".rand(1,1000));
  2974. $oMyObj->Set("org_id", 2);
  2975. $oMyObj->Set("status", 'production');
  2976. $this->ObjectToDB($oMyObj, $bReload = true);
  2977. echo "<p>Created: {$oMyObj->GetHyperLink()}</p>";
  2978. $sTicketRef = "I-abcdef";
  2979. echo "<p>Creating: $sTicketRef</p>";
  2980. $oMyObj = MetaModel::NewObject("Incident");
  2981. $oMyObj->Set("ref", $sTicketRef);
  2982. $oMyObj->Set("title", "my title");
  2983. $oMyObj->Set("description", "my description");
  2984. $oMyObj->Set("ticket_log", "my ticket log");
  2985. $oMyObj->Set("start_date", "2010-03-08 17:37:00");
  2986. $oMyObj->Set("status", "resolved");
  2987. $oMyObj->Set("caller_id", 1);
  2988. $oMyObj->Set("org_id", 1);
  2989. $oMyObj->Set("urgency", 3);
  2990. $oMyObj->Set("agent_id", 1);
  2991. $oMyObj->Set("close_date", "0000-00-00 00:00:00");
  2992. $oMyObj->Set("last_update", "2010-04-08 16:47:29");
  2993. $oMyObj->Set("solution", "branche ton pc!");
  2994. // External key given as a string -> should be casted to an integer
  2995. $oMyObj->Set("service_id", "1");
  2996. $oMyObj->Set("servicesubcategory_id", "1");
  2997. $oMyObj->Set("product", "");
  2998. $oMyObj->Set("impact", 2);
  2999. $oMyObj->Set("priority", 3);
  3000. $oMyObj->Set("related_problem_id", 0);
  3001. $oMyObj->Set("related_change_id", 0);
  3002. $oMyObj->Set("assignment_date", "");
  3003. $oMyObj->Set("resolution_date", "");
  3004. $oMyObj->Set("tto_escalation_deadline", "");
  3005. $oMyObj->Set("ttr_escalation_deadline", "");
  3006. $oMyObj->Set("closure_deadline", "");
  3007. $oMyObj->Set("resolution_code", "fixed");
  3008. $oMyObj->Set("user_satisfaction", "");
  3009. $oMyObj->Set("user_commment", "");
  3010. $oMyObj->Set("workgroup_id", 4);
  3011. $this->ObjectToDB($oMyObj, $bReload = true);
  3012. echo "<p>Created: {$oMyObj->GetHyperLink()}</p>";
  3013. }
  3014. }
  3015. class TestSetLinkset extends TestBizModel
  3016. {
  3017. static public function GetName()
  3018. {
  3019. return 'Itop - Link set from a string';
  3020. }
  3021. static public function GetDescription()
  3022. {
  3023. return 'Create a user account, setting its profile by the mean of a string (prerequisite to CSV import of linksets)';
  3024. }
  3025. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  3026. protected function DoExecute()
  3027. {
  3028. $oUser = new UserLocal();
  3029. $oUser->Set('login', 'patator'.time());
  3030. $oUser->Set('password', 'patator');
  3031. //$oUser->Set('contactid', 0);
  3032. //$oUser->Set('language', $sLanguage);
  3033. $sLinkSetSpec = "profileid:10;reason:service manager|profileid->name:Problem Manager;'reason:problem manager;glandeur";
  3034. $oAttDef = MetaModel::GetAttributeDef('UserLocal', 'profile_list');
  3035. $oSet = $oAttDef->MakeValueFromString($sLinkSetSpec, $bLocalizedValue = false);
  3036. $oUser->Set('profile_list', $oSet);
  3037. // Create a change to record the history of the User object
  3038. $this->ObjectToDB($oUser, $bReload = true);
  3039. echo "<p>Created: {$oUser->GetHyperLink()}</p>";
  3040. }
  3041. }
  3042. class TestEmailAsynchronous extends TestBizModel
  3043. {
  3044. static public function GetName()
  3045. {
  3046. return 'Itop - Asynchronous email';
  3047. }
  3048. static public function GetDescription()
  3049. {
  3050. return 'Queues a request to send an email';
  3051. }
  3052. static public function GetConfigFile() {return 'conf/production/config-itop.php';}
  3053. protected function DoExecute()
  3054. {
  3055. for ($i = 0 ; $i < 2 ; $i++)
  3056. {
  3057. $oMail = new Email();
  3058. $oMail->SetRecipientTO('romain.quetiez@combodo.com');
  3059. $oMail->SetRecipientFrom('romain.quetiez@combodo.com');
  3060. $oMail->SetRecipientCC('romainquetiez@yahoo.fr');
  3061. $oMail->SetSubject('automated test - '.$i);
  3062. $oMail->SetBody('this is one is entirely working fine '.time());
  3063. $iRes = $oMail->Send($aIssues, false);
  3064. switch ($iRes)
  3065. {
  3066. case EMAIL_SEND_OK:
  3067. echo "EMAIL_SEND_OK<br/>\n";
  3068. break;
  3069. case EMAIL_SEND_PENDING:
  3070. echo "EMAIL_SEND_PENDING<br/>\n";
  3071. break;
  3072. case EMAIL_SEND_ERROR:
  3073. echo "EMAIL_SEND_ERROR: <br/>\n";
  3074. foreach($aIssues as $sIssue)
  3075. {
  3076. echo "Issue: $sIssue<br/>\n";
  3077. }
  3078. break;
  3079. }
  3080. }
  3081. }
  3082. }
  3083. ?>