https://github.com/root-project/root
Tip revision: 54807d9b7051c0e88d7074c9d2205bbd884e0210 authored by Axel Naumann on 12 April 2022, 16:24:02 UTC
"Update ROOT version files to v6.26/02."
"Update ROOT version files to v6.26/02."
Tip revision: 54807d9
stressIOPlugins.cxx
// @(#)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 <cstdlib>
#include <snprintf.h>
#include <TROOT.h>
#include <TSystem.h>
#include <TH1.h>
#include <TH2.h>
#include <TFile.h>
#include <TMath.h>
#include <TF1.h>
#include <TF2.h>
#include <TCanvas.h>
#include <TPostScript.h>
#include <TTree.h>
#include <TChain.h>
#include <TTreeCache.h>
#include <TSystem.h>
#include <TApplication.h>
#include <TClassTable.h>
#include <Compression.h>
#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;i<kMAX;i++) header[i] = '.';
header[kMAX] = 0;
header[kMAX-1] = ' ';
printf("%s",header);
}
TFile *openTestFile(const char *fn, const char *title) {
printf("using %s\n", fn);
TFile *f = TFile::Open(gPfx + fn);
Bprint(0,"opened file with plugin class");
if (!f) {
printf("FAILED\n");
Bprint(0, title);
return 0;
}
printf("%s\n", f->ClassName());
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/root-eos/StressIOPluginsTestFiles/";
return 0;
}
if (p == "http" || p == "https") {
gPfx = p + "://root.cern.ch/files/StressIOPluginsTestFiles/";
return 0;
}
return -1;
}
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 || 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);
}