new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')), $oCondition = new BinaryExpression(new FieldExpression('column1', 'myTableAlias'), 'LIKE', new ScalarExpression('trash')), $aFullTextNeedles = array('column1'), $bToDelete = false, $aValues = array() ); $oQuery->AddCondition(Expression::FromOQL('DATE(NOW() - 1200 * 2) > \'2008-07-31\'')); $oSubQuery1 = new SQLQuery( $sTable = 'myTable1', $sTableAlias = 'myTable1Alias', $aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')), $oCondition = new TrueSQLExpression, $aFullTextNeedles = array(), $bToDelete = false, $aValues = array() ); $oSubQuery2 = new SQLQuery( $sTable = 'myTable2', $sTableAlias = 'myTable2Alias', $aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')), $oCondition = new TrueSQLExpression, $aFullTextNeedles = array(), $bToDelete = false, $aValues = array() ); $oQuery->AddInnerJoin($oSubQuery1, 'column1', 'column1_1'); $oQuery->AddLeftJoin($oSubQuery2, 'column2', 'column2_2'); $oQuery->DisplayHtml(); $oQuery->RenderDelete(); $oQuery->RenderUpdate(); echo '

'.$oQuery->RenderSelect().'

'; $oQuery->RenderSelect(array('column1')); $oQuery->RenderSelect(array('column1', 'column2')); } } class TestOQLParser extends TestFunction { static public function GetName() {return 'Check OQL parsing';} static public function GetDescription() {return 'Attempts a series of queries, and in particular those with a bad syntax';} protected function CheckQuery($sQuery, $bIsCorrectQuery) { $oOql = new OqlInterpreter($sQuery); try { $oTrash = $oOql->Parse(); // Not expecting a given format, otherwise use ParseExpression/ParseObjectQuery/ParseValueSetQuery MyHelpers::var_dump_html($oTrash, true); } catch (OQLException $OqlException) { if ($bIsCorrectQuery) { echo "

More info on this unexpected failure:
".$OqlException->getHtmlDesc()."

\n"; throw $OqlException; return false; } else { // Everything is fine :-) echo "

More info on this expected failure:
".$OqlException->getHtmlDesc()."

\n"; return true; } } // The query was correctly parsed, was it expected to be correct ? if ($bIsCorrectQuery) { return true; } else { throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)"); return false; } } protected function TestQuery($sQuery, $bIsCorrectQuery) { if (!$this->CheckQuery($sQuery, $bIsCorrectQuery)) { return false; } return true; } public function DoExecute() { $aQueries = array( 'SELECT toto' => true, 'SELECT toto WHERE toto.a = 1' => true, 'SELECT toto WHERE toto.a=1' => true, 'SELECT toto WHERE toto.a = "1"' => true, 'SELECT toto WHHHERE toto.a = "1"' => false, 'SELECT toto WHERE toto.a == "1"' => false, 'SELECT toto WHERE toto.a % 1' => false, //'SELECT toto WHERE toto.a LIKE 1' => false, 'SELECT toto WHERE toto.a like \'arg\'' => false, 'SELECT toto WHERE toto.a NOT LIKE "That\'s it"' => true, 'SELECT toto WHERE toto.a NOT LIKE "That\'s "it""' => false, 'SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""' => true, 'SELECT toto WHERE toto.a NOT LIKE \'That"s it\'' => true, 'SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'' => false, 'SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\'' => true, 'SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"' => false, 'SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"' => true, 'SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'' => false, 'SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\'' => true, 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true, 'SELECT toto WHERE toto.a NOT LIKE "\\""' => true, 'SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"' => true, 'SELECT toto WHERE toto.a NOT LIKE "\\\\\\""' => true, 'SELECT toto WHERE toto.a NOT LIKE ""' => true, 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true, "SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = 'lnkContactRealObject' AND UserRightsMatrixClassGrant.action = 'modify' AND UserRightsMatrixClassGrant.login = 'Denis'" => true, "SELECT A WHERE A.col1 = 'lit1' AND A.col2 = 'lit2' AND A.col3 = 'lit3'" => true, 'SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"' => true, //'SELECT toto WHERE toto.a > \'asd\'' => false, 'SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345' => true, 'SELECT Device JOIN Site ON Device.site = Site.id' => true, 'SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true, "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, "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, "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2" => true, "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2" => true, "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2" => true, 'SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"' => true, ); $iErrors = 0; foreach($aQueries as $sQuery => $bIsCorrectQuery) { $sIsOk = $bIsCorrectQuery ? 'good' : 'bad'; echo "

Testing query: $sQuery ($sIsOk)

\n"; $bRet = $this->TestQuery($sQuery, $bIsCorrectQuery); if (!$bRet) $iErrors++; } return ($iErrors == 0); } } class TestGenericItoMyModel extends TestBizModelGeneric { static public function GetName() { return 'Generic RO test on '.self::GetConfigFile(); } static public function GetConfigFile() {return '../config-test-mymodel.php';} } class TestGenericItopBigModel extends TestBizModelGeneric { static public function GetName() { return 'Generic RO test on '.self::GetConfigFile(); } static public function GetConfigFile() {return '../config-test-itopv06.php';} } class TestUserRightsMatrixItop extends TestUserRights { static public function GetName() { return 'User rights test on user rights matrix'; } static public function GetDescription() { return 'blah blah blah'; } public function DoPrepare() { parent::DoPrepare(); MetaModel::Startup('../config-test-itopv06.php'); } protected function DoExecute() { $sUser = 'Romain'; echo "

Totor: ".(UserRights::Login('Totor', 'toto') ? 'ok' : 'NO')."

\n"; echo "

Romain: ".(UserRights::Login('Romain', 'toto') ? 'ok' : 'NO')."

\n"; echo "

User: ".UserRights::GetUser()."

\n"; echo "

On behalf of...".UserRights::GetRealUser()."

\n"; echo "

Denis (impersonate) : ".(UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO')."

\n"; echo "

User: ".UserRights::GetUser()."

\n"; echo "

On behalf of...".UserRights::GetRealUser()."

\n"; UserRights::GetFilter('bizOrganization'); // returns a filter object $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization")); echo "

IsActionAllowed...".(UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

\n"; echo "

IsStimulusAllowed...".(UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

\n"; echo "

IsActionAllowedOnAttribute...".(UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

\n"; return true; } } /////////////////////////////////////////////////////////////////////////// // Test a complex biz model on the fly /////////////////////////////////////////////////////////////////////////// class TestMyBizModel extends TestBizModel { static public function GetName() { return 'A series of tests on a weird business model'; } static public function GetDescription() { return 'Attempts various operations and build complex queries'; } static public function GetConfigFile() {return '../config-test-mymodel.php';} function test_linksinfo() { echo "

Enum links

"; MyHelpers::var_dump_html(MetaModel::EnumReferencedClasses("cmdbTeam")); MyHelpers::var_dump_html(MetaModel::EnumReferencingClasses("Organization")); MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses()); MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses("cmdbContact")); MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses("cmdWorkshop")); MyHelpers::var_dump_html(MetaModel::GetLinkLabel("Liens_entre_contacts_et_workshop", "toworkshop")); } function test_list_attributes() { echo "

List attributes

"; foreach(MetaModel::ListAttributeDefs("cmdbTeam") as $sAttCode=>$oAttDef) { echo $oAttDef->GetLabel()." / ".$oAttDef->GetDescription()." / ".$oAttDef->GetType()."
\n"; } } function test_search() { echo "

Two searches

"; $oFilterAllDevs = new DBObjectSearch("cmdbTeam"); $oAllDevs = new DBObjectSet($oFilterAllDevs); echo "Found ".$oAllDevs->Count()." items.
\n"; while ($oDev = $oAllDevs->Fetch()) { $aValues = array(); foreach(MetaModel::GetAttributesList($oAllDevs->GetClass()) as $sAttCode) { $aValues[] = MetaModel::GetLabel(get_class($oDev), $sAttCode)." (".MetaModel::GetDescription(get_class($oDev), $sAttCode).") = ".$oDev->GetAsHTML($sAttCode); } echo $oDev->GetKey()." => ".implode(", ", $aValues)."
\n"; } // a second one $oMyFilter = new DBObjectSearch("cmdbContact"); //$oMyFilter->AddCondition("name", "aii", "Finishes with"); $oMyFilter->AddCondition("name", "aii"); $this->search_and_show_list($oMyFilter); } function test_reload() { echo "

Reload

"; $team = MetaModel::GetObject("cmdbContact", "2"); echo "Chargement de l'attribut headcount: {$team->Get("headcount")}
\n"; MyHelpers::var_dump_html($team); } function test_setattribute() { echo "

Set attribute and update

"; $team = MetaModel::GetObject("cmdbTeam", "2"); $team->Set("headcount", rand(1,1000)); $team->Set("email", "Luis ".rand(9,250)); MyHelpers::var_dump_html($team->ListChanges()); echo "New headcount = {$team->Get("headcount")}
\n"; echo "Computed name = {$team->Get("name")}
\n"; $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "test_setattribute / Made by robot #".rand(1,100)); $iChangeId = $oMyChange->DBInsert(); //MetaModel::StartDebugQuery(); $team->DBUpdateTracked($oMyChange); //MetaModel::StopDebugQuery(); echo "

Check the modified team

"; $oTeam = MetaModel::GetObject("cmdbTeam", "2"); MyHelpers::var_dump_html($oTeam); } function test_newobject() { $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "test_newobject / Made by robot #".rand(1,100)); $iChangeId = $oMyChange->DBInsert(); echo "

Create a new object (team)

"; $oNewTeam = MetaModel::NewObject("cmdbTeam"); $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000)); $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com"); $oNewTeam->Set("email", null); $oNewTeam->Set("owner", "ITOP"); $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value $iId = $oNewTeam->DBInsertTracked($oMyChange); echo "Created new team: $iId
"; echo "

Delete team #$iId

"; $oTeam = MetaModel::GetObject("cmdbTeam", $iId); $oTeam->DBDeleteTracked($oMyChange); echo "Deleted team: $iId
"; MyHelpers::var_dump_html($oTeam); } function test_updatecolumn() { $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "test_updatecolumn / Made by robot #".rand(1,100)); $iChangeId = $oMyChange->DBInsert(); $sNewEmail = "updatecol".rand(9,250)."@quedlaballe.com"; echo "

Update a the email: set to '$sNewEmail'

"; $oMyFilter = new DBObjectSearch("cmdbContact"); $oMyFilter->AddCondition("name", "o", "Contains"); echo "Candidates before:
"; $this->search_and_show_list($oMyFilter); MetaModel::BulkUpdateTracked($oMyChange, $oMyFilter, array("email" => $sNewEmail)); echo "Candidates after:
"; $this->search_and_show_list($oMyFilter); } function test_error() { trigger_error("Stop requested", E_USER_ERROR); } function test_changetracking() { echo "

Create a change

"; $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "Made by robot #".rand(1,100)); $iChangeId = $oMyChange->DBInsert(); echo "Created new change: $iChangeId
"; MyHelpers::var_dump_html($oMyChange); echo "

Create a new object (team)

"; $oNewTeam = MetaModel::NewObject("cmdbTeam"); $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000)); $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com"); $oNewTeam->Set("email", null); $oNewTeam->Set("owner", "ITOP"); $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value $iId = $oNewTeam->DBInsertTracked($oMyChange); echo "Created new team: $iId
"; echo "

Delete team #$iId

"; $oTeam = MetaModel::GetObject("cmdbTeam", $iId); $oTeam->DBDeleteTracked($oMyChange); echo "Deleted team: $iId
"; MyHelpers::var_dump_html($oTeam); } function test_zlist() { echo "

Test ZLists

"; $aZLists = MetaModel::EnumZLists(); foreach ($aZLists as $sListCode) { $aListInfos = MetaModel::GetZListInfo($sListCode); echo "

List '".$sListCode."' (".$aListInfos["description"].") of type '".$aListInfos["type"]."'

\n"; foreach (MetaModel::GetSubclasses("cmdbObjectHomeMade") as $sKlass) { $aItems = MetaModel::GetZListItems($sKlass, $sListCode); if (count($aItems) == 0) continue; echo "$sKlass - $sListCode : {".implode(", ", $aItems)."}
\n"; } } echo "

IsAttributeInZList()...

"; echo "Liens_entre_contacts_et_workshop::ws_info in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "ws_info") ? "yes" : "no")."
\n"; echo "Liens_entre_contacts_et_workshop::toworkshop in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "toworkshop") ? "yes" : "no")."
\n"; } function test_SibuSQL() { echo "

Simple But Structured Query Language

"; $oMyFilter = new DBObjectSearch("cmdbContact"); echo "Tous les contacts: ".$oMyFilter->ToSibuSQL()."
\n"; $oNewFilter = DBObjectSearch::FromSibuSQL($oMyFilter->ToSibuSQL()); echo "En passant par un filtre, ca revient en : ".$oNewFilter->ToSibuSQL()."
\n"; $this->search_and_show_list($oNewFilter); $sFilterDesc = "cmdbContact: name Begins with '$[debutnom:as:debut du nom]' AND ownername NotLike $[ddd::]"; echo "Construction d'un filtre a partir de sa description en SibuSQL: $sFilterDesc
\n"; MyHelpers::var_dump_html(DBObjectSearch::ListSibusQLParams($sFilterDesc)); $oNewFilter = DBObjectSearch::FromSibuSQL($sFilterDesc, array('ddd'=>123)); echo "Ca revient en: ".$oNewFilter->ToSibuSQL(); } function test_pkey() { echo "

Test search on pkey

"; $sExpr1 = "cmdbContact: pkey IN {40, 42}"; $sExpr2 = "cmdbContact: pkey NOTIN {40, 42}"; $this->search_and_show_list_from_sibusql($sExpr1); $this->search_and_show_list_from_sibusql($sExpr2); echo "Et maintenant, on fusionne....
\n"; $oSet1 = new CMDBObjectSet(DBObjectSearch::FromSibuSQL($sExpr1)); $oSet2 = new CMDBObjectSet(DBObjectSearch::FromSibuSQL($sExpr2)); $oIntersect = $oSet1->CreateIntersect($oSet2); $oDelta = $oSet1->CreateDelta($oSet2); $oMerge = clone $oSet1; $oMerge->Merge($oSet2); $oMerge->Merge($oSet2); echo "Set1 - Found ".$oSet1->Count()." items.
\n"; echo "Set2 - Found ".$oSet2->Count()." items.
\n"; echo "Intersect - Found ".$oIntersect->Count()." items.
\n"; echo "Delta - Found ".$oDelta->Count()." items.
\n"; echo "Merge - Found ".$oMerge->Count()." items.
\n"; //$this->show_list($oObjSet); } function test_relations() { echo "

Test relations

"; //MyHelpers::var_dump_html(MetaModel::EnumRelationQueries("cmdbObjectHomeMade", "Potes")); MyHelpers::var_dump_html(MetaModel::EnumRelationQueries("cmdbContact", "Potes")); $iMaxDepth = 9; echo "Max depth = $iMaxDepth
\n"; $oObj = MetaModel::GetObject("cmdbContact", 18); $aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth); echo $oObj->Get('name')." has some 'Potes'...
\n"; foreach ($aRels as $sClass => $aObjs) { echo "$sClass, count = ".count($aObjs)." => ".implode(', ', array_keys($aObjs))."
\n"; $oObjectSet = CMDBObjectSet::FromArray($sClass, $aObjs); $this->show_list($oObjectSet); } echo "

Test relations - same results, by the mean of a SibuSQL

"; $this->search_and_show_list_from_sibusql("cmdbContact: RELATED (Potes, $iMaxDepth) TO (cmdbContact: pkey = 18)"); } function test_linkedset() { echo "

Linked set attributes

\n"; $oObj = MetaModel::GetObject("cmdbContact", 18); echo "
Current workshops
\n"; $oSetWorkshopsCurr = $oObj->Get("myworkshops"); $this->show_list($oSetWorkshopsCurr); echo "
Setting workshops
\n"; $oNewLink = new cmdbLiens(); $oNewLink->Set('toworkshop', 2); $oNewLink->Set('function', 'mafonctioooon'); $oNewLink->Set('a1', 'tralala1'); $oNewLink->Set('a2', 'F7M'); $oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink)); $oObj->Set("myworkshops", $oSetWorkshops); $this->show_list($oSetWorkshops); echo "
New workshops
\n"; $oSetWorkshopsCurr = $oObj->Get("myworkshops"); $this->show_list($oSetWorkshopsCurr); $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "test_linkedset / Made by robot #".rand(1,100)); $iChangeId = $oMyChange->DBInsert(); $oObj->DBUpdateTracked($oMyChange); $oObj = MetaModel::GetObject("cmdbContact", 18); echo "
After the write
\n"; $oSetWorkshopsCurr = $oObj->Get("myworkshops"); $this->show_list($oSetWorkshopsCurr); } function test_object_lifecycle() { echo "

Test object lifecycle

"; MyHelpers::var_dump_html(MetaModel::GetStateAttributeCode("cmdbContact")); MyHelpers::var_dump_html(MetaModel::EnumStates("cmdbContact")); MyHelpers::var_dump_html(MetaModel::EnumStimuli("cmdbContact")); foreach(MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef) { echo "

Transition from $sStateCode

\n"; MyHelpers::var_dump_html(MetaModel::EnumTransitions("cmdbContact", $sStateCode)); } $oObj = MetaModel::GetObject("cmdbContact", 18); echo "Current state: ".$oObj->GetState()."... let's go to school..."; MyHelpers::var_dump_html($oObj->EnumTransitions()); $oObj->ApplyStimulus("toschool"); echo "New state: ".$oObj->GetState()."... let's get older..."; MyHelpers::var_dump_html($oObj->EnumTransitions()); $oObj->ApplyStimulus("raise"); echo "New state: ".$oObj->GetState()."... let's try to go further... (should give an error)"; MyHelpers::var_dump_html($oObj->EnumTransitions()); $oObj->ApplyStimulus("raise"); // should give an error } protected function DoExecute() { // $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); //$this->test_linksinfo(); //$this->test_list_attributes(); //$this->test_search(); //$this->test_reload(); //$this->test_newobject(); $this->test_setattribute(); //$this->test_updatecolumn(); //$this->test_error(); //$this->test_changetracking(); $this->test_zlist(); $this->test_SibuSQL(); //$this->test_pkey(); $this->test_relations(); $this->test_linkedset(); $this->test_object_lifecycle(); return true; } } /////////////////////////////////////////////////////////////////////////// // Test a complex biz model on the fly /////////////////////////////////////////////////////////////////////////// class TestQueriesOnFarm extends TestBizModel { static public function GetName() { return 'Farm test'; } static public function GetDescription() { return 'A series of tests on the farm business model (SQL generation)'; } static public function GetConfigFile() {return '../config-test-farm.php';} protected function DoPrepare() { parent::DoPrepare(); $this->ResetDB(); MetaModel::DBCheckIntegrity(); } protected $m_oChange; protected function ObjectToDB(CMDBObject $oNew) { if (!isset($this->m_oChange)) { new CMDBChange(); $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "Administrator"); $iChangeId = $oMyChange->DBInsertNoReload(); $this->m_oChange = $oMyChange; } $iId = $oNew->DBInsertTrackedNoReload($this->m_oChange); return $iId; } protected function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth) { $oNew = MetaModel::NewObject('Mammal'); $oNew->Set('species', $sSpecies); $oNew->Set('sex', $sSex); $oNew->Set('speed', $iSpeed); $oNew->Set('mother', $iMotherid); $oNew->Set('father', $iFatherId); $oNew->Set('name', $sName); $oNew->Set('height', $iHeight); $oNew->Set('birth', $sBirth); return $this->ObjectToDB($oNew); } protected function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId) { $oNew = MetaModel::NewObject('Bird'); $oNew->Set('species', $sSpecies); $oNew->Set('sex', $sSex); $oNew->Set('speed', $iSpeed); $oNew->Set('mother', $iMotherid); $oNew->Set('father', $iFatherId); return $this->ObjectToDB($oNew); } protected function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed) { $oNew = MetaModel::NewObject('FlyingBird'); $oNew->Set('species', $sSpecies); $oNew->Set('sex', $sSex); $oNew->Set('speed', $iSpeed); $oNew->Set('mother', $iMotherid); $oNew->Set('father', $iFatherId); $oNew->Set('flyingspeed', $iFlyingSpeed); return $this->ObjectToDB($oNew); } private function InsertGroup($sName, $iLeaderId) { $oNew = MetaModel::NewObject('Group'); $oNew->Set('name', $sName); $oNew->Set('leader', $iLeaderId); $iId = $oNew->DBInsertNoReload(); return $iId; } protected function CheckQuery($sQuery, $bIsCorrectQuery) { if ($bIsCorrectQuery) { echo "

$sQuery

\n"; } else { echo "

$sQuery

\n"; } try { //$oOql = new OqlInterpreter($sQuery); //$oTrash = $oOql->ParseObjectQuery(); //MyHelpers::var_dump_html($oTrash, true); $oMyFilter = DBObjectSearch::FromOQL($sQuery); } catch (OQLException $oOqlException) { if ($bIsCorrectQuery) { echo "

More info on this unexpected failure:
".$oOqlException->getHtmlDesc()."

\n"; throw $oOqlException; return false; } else { // Everything is fine :-) echo "

More info on this expected failure:\n"; echo "

\n"; echo "

\n"; return true; } } // The query was correctly parsed, was it expected to be correct ? if (!$bIsCorrectQuery) { throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)"); return false; } echo "

To OQL: ".$oMyFilter->ToOQL()."

"; $this->search_and_show_list($oMyFilter); //echo "

first pass

\n"; //MyHelpers::var_dump_html($oMyFilter, true); $sQuery1 = MetaModel::MakeSelectQuery($oMyFilter); //echo "

second pass

\n"; //MyHelpers::var_dump_html($oMyFilter, true); //$sQuery1 = MetaModel::MakeSelectQuery($oMyFilter); $sSerialize = $oMyFilter->serialize(); echo "

Serialized:$sSerialize

\n"; $oFilter2 = DBObjectSearch::unserialize($sSerialize); try { $sQuery2 = MetaModel::MakeSelectQuery($oFilter2); } catch (Exception $e) { echo "

Could not compute the query after unserialize

\n"; echo "

Query 1: $sQuery1

\n"; MyHelpers::var_cmp_html($oMyFilter, $oFilter2); throw $e; } //if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same! if ($sQuery1 != $sQuery2) { echo "

serialize/unserialize mismatch :-(

\n"; MyHelpers::var_cmp_html($sQuery1, $sQuery2); MyHelpers::var_cmp_html($oMyFilter, $oFilter2); return false; } return true; } protected function DoExecute() { // $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); echo "

Create protagonists...

"; $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19'); $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23'); $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23'); $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01'); $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11'); $this->InsertBird('rooster', 'male', 12, 0, 0); $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35); // Benchmarking // if (false) { define ('COUNT_BENCHMARK', 10); echo "

Parsing a long query, ".COUNT_BENCHMARK." times

"; $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)"; $fStart = MyHelpers::getmicrotime(); for($i=0 ; $i < COUNT_BENCHMARK ; $i++) { $oMyFilter = DBObjectSearch::FromOQL($sQuery); } $fDuration = MyHelpers::getmicrotime() - $fStart; $fParsingDuration = $fDuration / COUNT_BENCHMARK; echo "

Mean time by op: $fParsingDuration

"; } echo "

Test queries...

"; $aQueries = array( 'SELECT Animal' => true, 'SELECT Animal WHERE Animal.pkey = 1' => false, 'SELECT Animal WHERE Animal.id = 1' => true, 'SELECT Aniiimal' => false, 'SELECTe Animal' => false, 'SELECT * FROM Animal' => false, 'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true, 'SELECT Animal AS zoo WHERE species = \'human\'' => true, 'SELECT Animal AS zoo WHERE espece = \'human\'' => false, 'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true, 'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false, 'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true, 'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true, 'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false, 'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true, 'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true, 'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true, 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, 'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true, 'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true, 'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true, 'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true, 'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true, 'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true, 'SELECT Mammal AS m WHERE (1 + 2' => false, 'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true, 'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true, 'SELECT Mammal AS m WHERE 1/0' => true, 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, 'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true, 'SELECT Group JOIN Animal ON Group.leader = Animal.id' => true, 'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true, 'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false, 'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.pkey' => false, 'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true, 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false, 'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true, 'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false, 'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false, 'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false, 'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true, 'SELECT Group AS G WHERE G.leader_speed < 100000' => true, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true, 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true, 'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, 'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true, 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true, 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true, 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true, '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, '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, 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, '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, 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true, 'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true, '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, ); //$aQueries = array( // 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true, //); foreach($aQueries as $sQuery => $bIsCorrect) { $this->CheckQuery($sQuery, $bIsCorrect); } return true; } } /////////////////////////////////////////////////////////////////////////// // Test data load /////////////////////////////////////////////////////////////////////////// class TestBulkChangeOnFarm extends TestBizModel { static public function GetName() { return 'Farm test - data load'; } static public function GetDescription() { return 'Bulk load'; } static public function GetConfigFile() {return '../config-test-farm.php';} protected function DoPrepare() { parent::DoPrepare(); $this->ResetDB(); MetaModel::DBCheckIntegrity(); } protected function DoExecute() { // $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); // $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); $oParser = new CSVParser("#denomination,hauteur,age suzy,123,2009-01-01 chita,456, "); $oParser->SetSeparator(','); $aData = $oParser->ToArray(array('_name', '_height', '_birth')); MyHelpers::var_dump_html($aData); $oBulk = new BulkChange( 'Mammal', $aData, array('name' => '_name', 'height' => '_height', 'birth' => '_birth'), array('name'), array() ); $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); $oMyChange->Set("userinfo", "Testor"); $iChangeId = $oMyChange->DBInsert(); // echo "Created new change: $iChangeId
"; echo "

Planned for loading...

"; $aRes = $oBulk->Process(); print_r($aRes); echo "

Go for loading...

"; $aRes = $oBulk->Process($oMyChange); print_r($aRes); return true; $oRawData = array( 'Mammal', array('species', 'sex', 'speed', 'mother', 'father', 'name', 'height', 'birth'), "human,male,23,0,0,romulus,192,1971 human,male,23,0,0,remus,154,-50 human,male,23,0,0,julius,160,-49 human,female,23,0,0,cleopatra,142,-50 pig,female,23,0,0,confucius,50,2003" ); } } /////////////////////////////////////////////////////////////////////////// // Benchmark queries /////////////////////////////////////////////////////////////////////////// class TestItopEfficiency extends TestBizModel { static public function GetName() { return 'Itop - benchmark'; } static public function GetDescription() { return 'Measure time to perform the queries'; } static public function GetConfigFile() {return '../config-itop.php';} protected function DoBenchmark($sOqlQuery) { echo "

Testing query: $sOqlQuery

"; $fStart = MyHelpers::getmicrotime(); for($i=0 ; $i < COUNT_BENCHMARK ; $i++) { $oFilter = DBObjectSearch::FromOQL($sOqlQuery); } $fDuration = MyHelpers::getmicrotime() - $fStart; $fParsingDuration = $fDuration / COUNT_BENCHMARK; $fStart = MyHelpers::getmicrotime(); for($i=0 ; $i < COUNT_BENCHMARK ; $i++) { $sSQL = MetaModel::MakeSelectQuery($oFilter); } $fDuration = MyHelpers::getmicrotime() - $fStart; $fBuildDuration = $fDuration / COUNT_BENCHMARK; $fStart = MyHelpers::getmicrotime(); for($i=0 ; $i < COUNT_BENCHMARK ; $i++) { $res = CMDBSource::Query($sSQL); } $fDuration = MyHelpers::getmicrotime() - $fStart; $fQueryDuration = $fDuration / COUNT_BENCHMARK; // The fetch could not be repeated with the same results // But we've seen so far that is was very very quick to exec // So it makes sense to benchmark it a single time $fStart = MyHelpers::getmicrotime(); $aRow = CMDBSource::FetchArray($res); $fDuration = MyHelpers::getmicrotime() - $fStart; $fFetchDuration = $fDuration; $fStart = MyHelpers::getmicrotime(); for($i=0 ; $i < COUNT_BENCHMARK ; $i++) { $sOql = $oFilter->ToOQL(); } $fDuration = MyHelpers::getmicrotime() - $fStart; $fToOqlDuration = $fDuration / COUNT_BENCHMARK; echo "\n"; // Everything but the ToOQL (wich is interesting, anyhow) $fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration; return array( 'rows' => CMDBSource::NbRows($res), 'duration (s)' => round($fTotal, 4), 'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1), 'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1), 'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1), 'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1), 'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1), 'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1), ); } protected function DoExecute() { define ('COUNT_BENCHMARK', 3); echo "

The test will be repeated ".COUNT_BENCHMARK." times

"; $aQueries = array( 'SELECT CMDBChangeOpSetAttribute', 'SELECT CMDBChangeOpSetAttribute WHERE id=10', 'SELECT CMDBChangeOpSetAttribute WHERE id=123456789', 'SELECT CMDBChangeOpSetAttribute WHERE CMDBChangeOpSetAttribute.id=10', 'SELECT bizIncidentTicket', 'SELECT bizIncidentTicket WHERE id=1', 'SELECT bizPerson', 'SELECT bizPerson WHERE id=1', 'SELECT bizIncidentTicket JOIN bizPerson ON bizIncidentTicket.agent_id = bizPerson.id WHERE bizPerson.id = 5', ); $aStats = array(); foreach ($aQueries as $sOQL) { $aStats[$sOQL] = $this->DoBenchmark($sOQL); } $aData = array(); foreach ($aStats as $sOQL => $aResults) { $aValues = array(); $aValues['OQL'] = htmlentities($sOQL); foreach($aResults as $sDesc => $sInfo) { $aValues[$sDesc] = htmlentities($sInfo); } $aData[] = $aValues; } echo MyHelpers::make_table_from_assoc_array($aData); return true; } } /////////////////////////////////////////////////////////////////////////// // Test data load /////////////////////////////////////////////////////////////////////////// class TestItopWebServices extends TestWebServices { static public function GetName() { return 'Itop - web services'; } static public function GetDescription() { return 'Bulk load and ???'; } protected function DoExecSingleLoad($aLoadSpec) { $sTitle = 'Load: '.$aLoadSpec['class']; $sClass = $aLoadSpec['class']; $sCsvData = $aLoadSpec['csvdata']; $aPostData = array('class' => $sClass, 'csvdata' => $sCsvData); $sRes = self::DoPostRequestAuth('webservices/import.php', $aPostData); echo "

$sTitle

$sCsvData
$sRes
"; } protected function DoExecute() { $aLoads = array( array( 'class' => 'bizOrganization', 'csvdata' => "name;code\nWorldCompany;WCY" ), array( 'class' => 'bizLocation', 'csvdata' => "name;org_id;address\nParis;1;Centre de la Franca" ), array( 'class' => 'bizPerson', 'csvdata' => "email;name;first_name;org_id;phone\njohn.foo@starac.com;Foo;John;1;+33(1)23456789" ), array( 'class' => 'bizTeam', 'csvdata' => "name;org_id;location_id\nSquadra Azzura;1;1" ), array( 'class' => 'bizWorkgroup', 'csvdata' => "name;org_id;team_id\ntravailleurs alpins;1;6" ), array( 'class' => 'bizIncidentTicket', 'csvdata' => "name;title;type;org_id;initial_situation;start_date;next_update;caller_id;workgroup_id;agent_id\nOVSD-12345;server down;Network;1;server was found down;2009-04-10 12:00;2009-04-10 15:00;3;317;5" ), ); foreach ($aLoads as $aLoadSpec) { $this->DoExecSingleLoad($aLoadSpec); } return true; } } ?>