//OpenSCADA module Special.SystemTests file: test_DB.h /*************************************************************************** * Copyright (C) 2005-2022 by Roman Savochenko, * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef TEST_DB_H #define TEST_DB_H #include namespace KernelTest { //************************************************* //* TestDB: Full database test. * //************************************************* class TestDB : public TFunction { public: TestDB( ) : TFunction("DB",SSPC_ID) { ioAdd(new IO("rez",trS("Result"),IO::String,IO::Return)); ioAdd(new IO("type",trS("DB type"),IO::String,IO::Default,"SQLite")); ioAdd(new IO("addr",trS("DB address"),IO::String,IO::Default,"./DATA/test.db")); ioAdd(new IO("table",trS("DB table"),IO::String,IO::Default,"test")); ioAdd(new IO("size",trS("Records number"),IO::Integer,IO::Default,"1000")); } string name( ) { return _("DB test"); } string descr( ) { return _("Complete database test. Performs:\n" " - create/open DB;\n" " - create/open table;\n" " - create multiple records for the determined structure;\n" " - update multiple records;\n" " - update multiple records by a request key;\n" " - get and check values for multiple records;\n" " - seek records;\n" " - seek records in preload;\n" " - modify a record and the table structure;\n" " - remove multiple records;\n" " - close/remove table;\n" " - close/remove DB."); } void calc( TValFunc *val ) { try { mod->mess(id(),_("Test: Start")); //Get test param string t_bd = val->getS(1); string n_bd = "test_bd"; string bd_addr = val->getS(2); string n_tbl = val->getS(3); int experem = val->getI(4); AutoHD bd = SYS->db().at().modAt(t_bd); mod->mess(id(),_("Open the DB '%s'."),n_bd.c_str()); bd.at().open(n_bd); bd.at().at(n_bd).at().setAddr(bd_addr); bd.at().at(n_bd).at().enable(); mod->mess(id(),_("Open the table '%s'."),n_tbl.c_str()); bd.at().at(n_bd).at().open(n_tbl, true); mod->mess(id(),_("Connect to the table '%s'."),n_tbl.c_str()); AutoHD tbl = bd.at().at(n_bd).at().at(n_tbl); mod->mess(id(),_("Create a DB configuration.")); TConfig bd_cfg; bd_cfg.elem().fldAdd(new TFld("name",_("Name"),TFld::String,TCfg::Key,i2s(limObjID_SZ).c_str())); bd_cfg.elem().fldAdd(new TFld("descr",_("Description"),TFld::String,0,i2s(limObjNm_SZ).c_str())); bd_cfg.elem().fldAdd(new TFld("val",_("Value"),TFld::Real,0,"10.2","5")); bd_cfg.elem().fldAdd(new TFld("id",_("Identifier"),TFld::Integer,0,"7","34")); bd_cfg.elem().fldAdd(new TFld("stat",_("State"),TFld::Boolean,0,"1","1")); bd_cfg.elem().fldAdd(new TFld("reqKey",_("Request's key"),TFld::String,0,"100")); bd_cfg.elem().fldAdd(new TFld("reqVal",_("Request's value"),TFld::String,0,"100")); //Test for create records mod->mess(id(),_("Create records.")); int64_t ctime = TSYS::curTime(); for(int iFld = 0; iFld < experem; iFld++) { bd_cfg.cfg("name").setS("Sh"+i2s(iFld)); bd_cfg.cfg("descr").setS("Shifr '"+i2s(iFld)+"'"); bd_cfg.cfg("val").setR(sqrt(iFld)); bd_cfg.cfg("id").setI(iFld); bd_cfg.cfg("stat").setB((iFld%2)==0?true:false); bd_cfg.cfg("reqKey").setS(iFld<(experem/2)?"req0":"req1"); bd_cfg.cfg("reqVal").setS(iFld<(experem/2)?"Request 0 value":"Request 1 value"); tbl.at().fieldSet(bd_cfg); } mod->mess(id(),_("Created %d records for time %f sec."),experem,1e-6*(TSYS::curTime()-ctime)); //Check for update fields mod->mess(id(),_("Update records.")); ctime = TSYS::curTime(); for(int iFld = 0; iFld < experem; iFld++) { bd_cfg.cfg("name").setS("Sh"+i2s(iFld)); bd_cfg.cfg("descr").setS("New shifr \""+i2s(iFld)+"\""); bd_cfg.cfg("val").setR(2.*sqrt(iFld)); bd_cfg.cfg("id").setI(2*iFld); bd_cfg.cfg("stat").setB((iFld%2)==0?false:true); bd_cfg.cfg("reqKey").setView(false); bd_cfg.cfg("reqVal").setView(false); tbl.at().fieldSet(bd_cfg); } mod->mess(id(),_("Updated %d records for time %f sec."),experem,1e-6*(TSYS::curTime()-ctime)); //Check for update fields, by request key mod->mess(id(),_("Update records by a request key for %d records."), experem/2); ctime = TSYS::curTime(); bd_cfg.cfgViewAll(false); bd_cfg.cfg("reqKey").setReqKey(true); bd_cfg.cfg("reqKey").setS("req0", TCfg::ForceUse|TCfg::ExtValTwo); bd_cfg.cfg("reqKey").setS("reqNew0", TCfg::ForceUse); bd_cfg.cfg("reqVal").setS("Request new 0 value", TCfg::ForceUse); tbl.at().fieldSet(bd_cfg); mod->mess(id(),_("Updated %d records by a request key for time %f sec."),experem/2,1e-6*(TSYS::curTime()-ctime)); bd_cfg.cfg("reqKey").setReqKey(false); bd_cfg.cfg("reqKey").setExtVal(false); bd_cfg.cfgViewAll(true); //Check for get fields mod->mess(id(),_("Check records.")); ctime = TSYS::curTime(); for(int iFld = 0; iFld < experem; iFld++) { bd_cfg.cfg("name").setS("Sh"+i2s(iFld)); tbl.at().fieldGet(bd_cfg); if(experem > 155 && iFld == 155) mod->mess(id(),_("Record #155='%s'; Descr='%s'; Value=%f; Id=%d; Stat=%d."),//; reqKey='%s'; reqVal='%s'."), bd_cfg.cfg("name").getS().c_str(), bd_cfg.cfg("descr").getS().c_str(), bd_cfg.cfg("val").getR(), bd_cfg.cfg("id").getI(), bd_cfg.cfg("stat").getB());/*, bd_cfg.cfg("reqKey").getS().c_str(), bd_cfg.cfg("reqVal").getS().c_str());*/ //By some GLibC crashes if(bd_cfg.cfg("name").getS() != (string("Sh")+i2s(iFld))) throw TError(nodePath().c_str(),_("Field '%s' != '%s' error."), bd_cfg.cfg("name").getS().c_str(),(string("Sh")+i2s(iFld)).c_str()); if(bd_cfg.cfg("descr").getS() != (string("New shifr \"")+i2s(iFld)+"\"")) throw TError(nodePath().c_str(),_("Field '%s' != '%s' error."), bd_cfg.cfg("descr").getS().c_str(),(string("New shifr ")+i2s(iFld)).c_str()); //ceil(100.*bd_cfg.cfg("val").getR()) != ceil(2.*sqrt(iFld)) || if(bd_cfg.cfg("id").getI() != (2*iFld)) throw TError(nodePath().c_str(),_("Field %d != %d error."),bd_cfg.cfg("id").getI(), (2*iFld) ); if(bd_cfg.cfg("stat").getB() != ((iFld%2)==0?false:true)) throw TError(nodePath().c_str(),_("Field %d != %d error."),bd_cfg.cfg("stat").getB(),((iFld%2)==0?false:true)); if(bd_cfg.cfg("reqKey").getS() != ((iFld<(experem/2))?"reqNew0":"req1")) throw TError(nodePath().c_str(), _("Field '%s' != '%s' error."), bd_cfg.cfg("reqKey").getS().c_str(), ((iFld<(experem/2))?"reqNew0":"req1")); if(bd_cfg.cfg("reqVal").getS() != ((iFld<(experem/2))?"Request new 0 value":"Request 1 value")) throw TError(nodePath().c_str(), _("Field '%s' != '%s' error."), bd_cfg.cfg("reqVal").getS().c_str(), ((iFld<(experem/2))?"Request new 0 value":"Request 1 value")); } mod->mess(id(),_("Got %d records for time %f sec."),experem,1e-6*(TSYS::curTime()-ctime)); //Seek all records mod->mess(id(), _("Seek records.")); ctime = TSYS::curTime(); bd_cfg.cfg("name").setKeyUse(false); int pos = 0; while(tbl.at().fieldSeek(pos,bd_cfg)) pos++; mod->mess(id(), _("Sought %d records for time %f sec."), pos, 1e-6*(TSYS::curTime()-ctime)); //Seek in preload all records mod->mess(id(), _("Seek records in preload.")); ctime = TSYS::curTime(); pos = 0; while(tbl.at().fieldSeek(pos,bd_cfg,TSYS::addr2str(&bd_cfg))) pos++; bd_cfg.cfg("name").setKeyUse(true); mod->mess(id(), _("Sought %d records in preload for time %f sec."), pos, 1e-6*(TSYS::curTime()-ctime)); //Check for fix structure mod->mess(id(),_("Change DB structure.")); //Add column bd_cfg.elem().fldAdd(new TFld("fix",_("DB fix test"),TFld::String,0,"20")); bd_cfg.cfg("name").setS("Sh1"); tbl.at().fieldSet(bd_cfg); bd_cfg.cfg("name").setS("Sh2"); tbl.at().fieldGet(bd_cfg); if(bd_cfg.cfg("name").getS() != "Sh2" || bd_cfg.cfg("descr").getS() != "New shifr \"2\"" || bd_cfg.cfg("id").getI() != 4 || bd_cfg.cfg("stat").getB() != false) { mod->mess(id(),_("Record #2='%s'; Descr='%s'; Value=%f; Id=%d; Stat=%d."), bd_cfg.cfg("name").getS().c_str(), bd_cfg.cfg("descr").getS().c_str(), bd_cfg.cfg("val").getR(), bd_cfg.cfg("id").getI(), bd_cfg.cfg("stat").getB()); throw TError(nodePath().c_str(),_("Error adding a column.")); } else mod->mess(id(),_("OK adding a column.")); //Del column bd_cfg.elem().fldDel(bd_cfg.elem().fldId("fix")); bd_cfg.cfg("name").setS("Sh1"); tbl.at().fieldSet(bd_cfg); bd_cfg.cfg("name").setS("Sh2"); tbl.at().fieldGet(bd_cfg); if(bd_cfg.cfg("name").getS() != "Sh2" || bd_cfg.cfg("descr").getS() != "New shifr \"2\"" || bd_cfg.cfg("id").getI() != 4 || bd_cfg.cfg("stat").getB() != false) { mod->mess(id(),"Record #2='%s'; Descr='%s'; Value=%f; Id=%d; Stat=%d.", bd_cfg.cfg("name").getS().c_str(), bd_cfg.cfg("descr").getS().c_str(), bd_cfg.cfg("val").getR(), bd_cfg.cfg("id").getI(), bd_cfg.cfg("stat").getB() ); throw TError(nodePath().c_str(),_("Error deleting a column.")); } else mod->mess(id(),_("OK deleting a column.")); //Check List //vector ls_elem; //tbl.at().fieldList("name",ls_elem); //if(ls_elem.size() != experem) mod->mess(id(),_("Error list size!")); //Delete fields ctime = TSYS::curTime(); for(int iFld = 0; iFld < experem; iFld++) { bd_cfg.cfg("name").setS("Sh"+i2s(iFld),true); tbl.at().fieldDel(bd_cfg); } mod->mess(id(),_("Deleted %d records for time %f sec."),experem,1e-6*(TSYS::curTime()-ctime)); tbl.free(); mod->mess(id(),_("Close and delete the table '%s'."),n_tbl.c_str()); bd.at().at(n_bd).at().close(n_tbl,true); mod->mess(id(),_("Close and delete the DB '%s'."),n_bd.c_str()); bd.at().close(n_bd,true); bd.free(); mod->mess(id(),_("Test: Passed")); val->setS(0,_("Passed")); } catch(TError err) { mod->mess(id(),_("Test: Failed: %s"),err.mess.c_str()); val->setS(0,TSYS::strMess(_("Failed: %s"),err.mess.c_str())); } } }; } #endif //TEST_DB_H