// @(#)root/test:$Id$ // Author: David Smith 20/10/14 ///////////////////////////////////////////////////////////////// // //___A test for I/O plugins by reading files___ // // The files used in this test have been generated by // stress.cxx and preplaced on some data servers. // stressIOPlugins reads the remote files via various data // access protocols to test ROOT IO plugins. The data read are // tested via tests based on some of stress.cxx tests. // // Can be run as: // stressIOPlugins [name] // // The name parameter is a protocol name, as expected // in a url. The supported names are: xroot, root, http, https. // If the name is omitted a selection of schemes are tested // based on feature availability: // // feature protocol multithreaded test available // // xrootd root no // davix http no // // An example of output of a non multithreaded test, when all the tests // run OK is shown below: // // **************************************************************************** // * Starting stressIOPlugins test for protocol http // * Test files will be read from: // * http://root.cern.ch/files/StressIOPluginsTestFiles/ // **************************************************************************** // Test 1 : Check size & compression factor of a Root file........ using stress_2.root // : opened file with plugin class......................... TDavixFile // : Check size & compression factor of a Root file........ OK // Test 2 : Test graphics & Postscript............................ using stress_5.root // : opened file with plugin class......................... TDavixFile // : Test graphics & Postscript............................ OK // Test 3 : Trees split and compression modes..................... using Event_8a.root // : opened file with plugin class......................... TDavixFile // : Trees split and compression modes..................... using Event_8b.root // : opened file with plugin class......................... TDavixFile // : Trees split and compression modes..................... OK // Test 4 : Filename formats when adding files to TChain.......... using Event_8a.root and Event_8b.root // : treename in chain..................................... OK // : treename to AddFile................................... OK // : treename in filenames, slash-suffix style............. OK // : bad treename to AddFile, good in filename............. OK // : treename and url query in filename.................... OK // : treename given in url frag in filename................ OK // : filename with a url query in Add...................... OK // **************************************************************************** //_____________________________batch only_____________________ #ifndef __CINT__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Event.h" R__LOAD_LIBRARY( libEvent ) void stressIOPlugins(); void stressIOPluginsForProto(const char *protoName = 0, int multithread = 0); void stressIOPlugins1(); void stressIOPlugins2(); void stressIOPlugins3(); void stressIOPlugins4(); void stressIOPlugins5(); void cleanup(); int main(int argc, char **argv) { std::string inclRootSys = ("-I" + TROOT::GetRootSys() + "/test").Data(); TROOT::AddExtraInterpreterArgs({inclRootSys}); gROOT->SetBatch(); TApplication theApp("App", &argc, argv); const char *proto = 0; if (argc > 1) proto = argv[1]; stressIOPluginsForProto(proto); return 0; } #endif class TH1; class TTree; //_______________________ common part_________________________ Double_t ntotin=0, ntotout=0; TString gPfx,gCurProtoName; void Bprint(Int_t id, const char *title) { // Print test program number and its title const Int_t kMAX = 65; char header[80]; if (id > 0) { snprintf(header,80,"Test %2d : %s",id,title); } else { snprintf(header,80," : %s",title); } Int_t nch = strlen(header); for (Int_t i=nch;iClassName()); Bprint(0, title); return f; } Bool_t isFeatureAvailable(const char *name) { TString configfeatures = gROOT->GetConfigFeatures(); return configfeatures.Contains(name); } int setPath(const char *proto) { if (!proto) return -1; TString p(proto); gCurProtoName = p; if (p == "root" || p == "xroot") { gPfx = p + "://eospublic.cern.ch//eos/opstest/dhsmith/StressIOPluginsTestFiles/"; return 0; } if (p == "http" || p == "https") { gPfx = p + "://root.cern.ch/files/StressIOPluginsTestFiles/"; return 0; } return -1; } Bool_t running_as_sftnight_with_kerberos() { UserGroup_t *ug = gSystem->GetUserInfo((const char*)0); if (!ug) { return kFALSE; } if (ug->fUser != "sftnight") { delete ug; return kFALSE; } delete ug; return (gSystem->Exec("(klist | grep sftnight@CERN.CH) > /dev/null 2>&1") == 0); } void stressIOPluginsForProto(const char *protoName /*=0*/, int multithread /*=0*/) { //Main control function invoking all test programs if (!protoName) { if (isFeatureAvailable("xrootd")) { stressIOPluginsForProto("root"); } else { printf("* Skipping root protocol test because 'xrootd' feature not available\n"); } if (isFeatureAvailable("davix")) { stressIOPluginsForProto("http"); } else { printf("* Skipping http protocol test because 'davix' feature not available\n"); } return; } if (setPath(protoName)) { printf("No server and path available to test protocol %s\n", protoName); return; } if (multithread) { printf("No multithreaded tests are available\n"); return; } printf("****************************************************************************\n"); printf("* Starting stressIOPlugins test for protocol %s\n", protoName); printf("* Test files will be read from:\n"); printf("* %s\n", gPfx.Data()); printf("****************************************************************************\n"); stressIOPlugins1(); stressIOPlugins2(); stressIOPlugins3(); stressIOPlugins4(); stressIOPlugins5(); cleanup(); printf("****************************************************************************\n"); } void stressIOPlugins() { stressIOPluginsForProto((const char*)0,0); } //////////////////////////////////////////////////////////////////////////////// ///based on stress2() ///check length and compression factor in stress.root void stressIOPlugins1() { const char *title = "Check size & compression factor of a Root file"; Bprint(1, title); TFile *f = openTestFile("stress_2.root", title); if (!f) { printf("FAILED\n"); return; } Long64_t last = f->GetEND(); Float_t comp = f->GetCompressionFactor(); Bool_t OK = kTRUE; Long64_t lastgood = 9428; if (last lastgood+200 || comp <2.0 || comp > 2.4) OK = kFALSE; if (OK) printf("OK\n"); else { printf("FAILED\n"); printf("%-8s last =%lld, comp=%f\n"," ",last,comp); } delete f; } //////////////////////////////////////////////////////////////////////////////// /// based on stress5() /// Test of Postscript. /// Make a complex picture. Verify number of lines on ps file /// Testing automatically the graphics package is a complex problem. /// The best way we have found is to generate a Postscript image /// of a complex canvas containing many objects. /// The number of lines in the ps file is compared with a reference run. /// A few lines (up to 2 or 3) of difference may be expected because /// Postscript works with floats. The date and time of the run are also /// different. /// You can also inspect visually the ps file with a ps viewer. void stressIOPlugins2() { const char *title = "Test graphics & Postscript"; Bprint(2,title); TCanvas *c1 = new TCanvas("c1","stress canvas",800,600); gROOT->LoadClass("TPostScript","Postscript"); TString psfname = TString::Format("stressIOPlugins-%d.ps", gSystem->GetPid()); TPostScript ps(psfname,112); //Get objects generated in previous test TFile *f = openTestFile("stress_5.root",title); if (!f) { printf("FAILED\n"); return; } TF1 *f1form = (TF1*)f->Get("f1form"); TF2 *f2form = (TF2*)f->Get("f2form"); TH1F *h1form = (TH1F*)f->Get("h1form"); TH2F *h2form = (TH2F*)f->Get("h2form"); //Divide the canvas in subpads. Plot with different options c1->Divide(2,2); c1->cd(1); f1form->Draw(); c1->cd(2); h1form->Draw(); c1->cd(3); h2form->Draw("box"); f2form->Draw("cont1same"); c1->cd(4); f2form->Draw("surf"); ps.Close(); //count number of lines in ps file FILE *fp = fopen(psfname,"r"); if (!fp) { printf("FAILED\n"); printf("%-8s could not open %s\n"," ",psfname.Data()); delete c1; delete f; return; } char line[260]; Int_t nlines = 0; Int_t nlinesGood = 632; while (fgets(line,255,fp)) { nlines++; } fclose(fp); ntotin += f->GetBytesRead(); ntotout += f->GetBytesWritten(); Bool_t OK = kTRUE; if (nlines < nlinesGood-110 || nlines > nlinesGood+110) OK = kFALSE; if (OK) printf("OK\n"); else { printf("FAILED\n"); printf("%-8s nlines in %s file = %d\n"," ",psfname.Data(),nlines); } delete c1; delete f; } //////////////////////////////////////////////////////////////////////////////// Int_t test3read(const TString &fn, const char *title) { // Read the event file // Loop on all events in the file (reading everything). // Count number of bytes read Int_t nevent = 0; TFile *hfile = openTestFile(fn,title); if (!hfile) { return 0; } TTree *tree; hfile->GetObject("T",tree); Event *event = 0; tree->SetBranchAddress("event",&event); Int_t nentries = (Int_t)tree->GetEntries(); Int_t nev = TMath::Max(nevent,nentries); //activate the treeCache Int_t cachesize = 10000000; //this is the default value: 10 MBytes tree->SetCacheSize(cachesize); TTreeCache::SetLearnEntries(1); //one entry is sufficient to learn TTreeCache *tc = (TTreeCache*)hfile->GetCacheRead(); tc->SetEntryRange(0,nevent); Int_t nb = 0; for (Int_t ev = 0; ev < nev; ev++) { nb += tree->GetEntry(ev); //read complete event in memory } ntotin += hfile->GetBytesRead(); delete event; delete hfile; return nb; } //////////////////////////////////////////////////////////////////////////////// /// based on stress8() void stressIOPlugins3() { const char *title = "Trees split and compression modes"; Bprint(3,title); Int_t nbr0 = test3read("Event_8a.root",title); Event::Reset(); Int_t nbr1 = test3read("Event_8b.root",title); Event::Reset(); Bool_t OK = kTRUE; if (nbr0 == 0 || nbr0 != nbr1) OK = kFALSE; if (OK) printf("OK\n"); else { printf("FAILED\n"); printf("%-8s nbr0=%d, nbr1=%d\n"," ",nbr0,nbr1); } } //////////////////////////////////////////////////////////////////////////////// void stressIOPlugins4() { Long64_t nent; Bool_t tryquery = kTRUE; Bool_t trywildcard = kFALSE; Bool_t tryqueryInAdd = kFALSE; Bool_t tryziparchive = kFALSE; const char *title = "Filename formats when adding files to TChain"; Bprint(4,title); printf("using Event_8a.root and Event_8b.root\n"); if (gCurProtoName == "xroot" || gCurProtoName == "root") { trywildcard = kTRUE; tryqueryInAdd = kTRUE; tryziparchive = kTRUE; } if (gCurProtoName == "http" || gCurProtoName == "https") { tryqueryInAdd = kTRUE; } { Bprint(0,"treename in chain"); TChain mychain("T"); mychain.AddFile(gPfx + "Event_8a.root"); mychain.AddFile(gPfx + "Event_8b.root"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } { Bprint(0,"treename to AddFile"); TChain mychain("nosuchtree"); mychain.AddFile(gPfx + "Event_8a.root", TTree::kMaxEntries, "T"); mychain.AddFile(gPfx + "Event_8b.root", TTree::kMaxEntries, "T"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } { Bprint(0,"treename in filenames, slash-suffix style"); TChain mychain("nosuchtree"); mychain.AddFile(gPfx + "Event_8a.root/T"); mychain.AddFile(gPfx + "Event_8b.root/T"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } { Bprint(0,"bad treename to AddFile, good in filename"); TChain mychain("nosuchtree"); mychain.AddFile(gPfx + "Event_8a.root/T", TTree::kMaxEntries, "nosuchtree2"); mychain.AddFile(gPfx + "Event_8b.root/T", TTree::kMaxEntries, "nosuchtree2"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (tryquery) { Bprint(0,"treename and url query in filename"); TChain mychain("nosuchtree"); mychain.AddFile(gPfx + "Event_8a.root/T?myq=xyz"); mychain.AddFile(gPfx + "Event_8b.root/T?myq=xyz"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (tryquery) { Bprint(0,"treename given in url frag in filename"); TChain mychain("nosuchtree"); mychain.AddFile(gPfx + "Event_8a.root?myq=xyz#T"); mychain.AddFile(gPfx + "Event_8b.root?myq=xyz#T"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (tryqueryInAdd) { Bprint(0,"filename with a url query in Add"); TChain mychain("T"); mychain.Add(gPfx + "Event_8a.root?myq=xyz"); mychain.Add(gPfx + "Event_8b.root?myq=xyz"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (trywildcard) { Bprint(0,"wildcarded filename"); TChain mychain("T"); mychain.Add(gPfx + "Event_8*ot"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (trywildcard) { Bprint(0,"wildcarded filename with treename"); TChain mychain("nosuchtree"); mychain.Add(gPfx + "Event_8*.root/T"); nent = mychain.GetEntries(); if (nent != 200) { printf("FAILED\n"); } else { printf("OK\n"); } } if (tryziparchive) { Bprint(0,"zip archive"); printf("using multi_8.zip\n"); Bprint(0,"sub-file name in fragment"); { TChain mychain("T"); mychain.Add(gPfx + "multi_8.zip#Event_8a.root"); nent = mychain.GetEntries(); if (nent != 100) { printf("FAILED\n"); } else { printf("OK\n"); } } Bprint(0,"sub-file index in query"); { TChain mychain("T"); mychain.AddFile(gPfx + "multi_8.zip?myq=xyz&zip=0"); nent = mychain.GetEntries(); if (nent != 100) { printf("FAILED\n"); } else { printf("OK\n"); } } } } //////////////////////////////////////////////////////////////////////////////// void stressIOPlugins5() { Bool_t tryziparchive = kFALSE; const char *title = "Read content from a zip archive"; Bprint(5,title); if (gCurProtoName == "xroot" || gCurProtoName == "root") { tryziparchive = kTRUE; } if (!tryziparchive) { printf("skipping\n"); return; } TFile *hfile = openTestFile("multi_8.zip?&zip=1","find tree"); if (!hfile) { printf("FAILED\n"); return; } TTree *tree = 0; hfile->GetObject("T",tree); if (!tree) { printf("FAILED\n"); delete hfile; return; } tree->SetCacheSize(0); Int_t nentries = (Int_t)tree->GetEntries(); if (nentries != 100) { printf("FAILED\n"); delete hfile; return; } else { printf("OK\n"); } Event *event = 0; tree->SetBranchAddress("event",&event); tree->GetEntry(0); Bprint(0,"read event (no cache)"); if (!event || event->GetNtrack() != 603) { printf("FAILED\n"); } else { printf("OK\n"); } delete event; delete hfile; } void cleanup() { TString psfname = TString::Format("stressIOPlugins-%d.ps", gSystem->GetPid()); gSystem->Unlink(psfname); }