dalitests.cpp 106 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. /*
  14. * Dali Quick Regression Suite: Tests Dali functionality on a programmatic way.
  15. *
  16. * Add as much as possible here to avoid having to run the Hthor/Thor regressions
  17. * all the time for Dali tests, since most of it can be tested quickly from here.
  18. */
  19. #ifdef _USE_CPPUNIT
  20. #include "mpbase.hpp"
  21. #include "mpcomm.hpp"
  22. #include "daclient.hpp"
  23. #include "dadfs.hpp"
  24. #include "dafdesc.hpp"
  25. #include "dasds.hpp"
  26. #include "danqs.hpp"
  27. #include "dautils.hpp"
  28. #include "unittests.hpp"
  29. //#define COMPAT
  30. // ======================================================================= Support Functions / Classes
  31. static __int64 subchangetotal;
  32. static unsigned subchangenum;
  33. static CriticalSection subchangesect;
  34. static IRemoteConnection *Rconn;
  35. static IDistributedFileDirectory & dir = queryDistributedFileDirectory();
  36. static IUserDescriptor *user = createUserDescriptor();
  37. static unsigned initCounter = 0; // counter for initialiser
  38. // Declared in dadfs.cpp *only* when CPPUNIT is active
  39. extern void removeLogical(const char *fname, IUserDescriptor *user);
  40. void daliClientInit()
  41. {
  42. // Only initialise on first pass
  43. if (initCounter != 0)
  44. return;
  45. InitModuleObjects();
  46. user->set("user", "passwd");
  47. // Connect to local Dali
  48. SocketEndpoint ep;
  49. ep.set(".", 7070);
  50. SocketEndpointArray epa;
  51. epa.append(ep);
  52. Owned<IGroup> group = createIGroup(epa);
  53. initClientProcess(group, DCR_Other);
  54. initCounter++;
  55. }
  56. void daliClientEnd()
  57. {
  58. if (!initCounter)
  59. return;
  60. else if (1 == initCounter) // Only destroy on last pass
  61. {
  62. // Cleanup
  63. releaseAtoms();
  64. closedownClientProcess();
  65. setNodeCaching(false);
  66. }
  67. else
  68. initCounter--;
  69. }
  70. interface IChecker
  71. {
  72. virtual void title(unsigned n,const char *s)=0;
  73. virtual void add(const char *s,__int64 v)=0;
  74. virtual void add(const char *s,const char* v)=0;
  75. virtual void add(unsigned n,const char *s,__int64 v)=0;
  76. virtual void add(unsigned n,const char *s,const char* v)=0;
  77. virtual void error(const char *txt)=0;
  78. };
  79. void checkFilePart(IChecker *checker,IDistributedFilePart *part,bool blocked)
  80. {
  81. StringBuffer tmp;
  82. checker->add("getPartIndex",part->getPartIndex());
  83. unsigned n = part->numCopies();
  84. checker->add("numCopies",part->numCopies());
  85. checker->add("maxCopies",n);
  86. RemoteFilename rfn;
  87. for (unsigned copy=0;copy<n;copy++) {
  88. INode *node = part->queryNode(copy);
  89. if (node)
  90. checker->add(copy,"queryNode",node->endpoint().getUrlStr(tmp.clear()).str());
  91. else
  92. checker->error("missing node");
  93. checker->add(copy,"getFilename",part->getFilename(rfn,copy).getRemotePath(tmp.clear()).str());
  94. }
  95. checker->add("getPartName",part->getPartName(tmp.clear()).str());
  96. #ifndef COMPAT
  97. checker->add("getPartDirectory",part->getPartDirectory(tmp.clear()).str());
  98. #endif
  99. checker->add("queryProperties()",toXML(&part->queryAttributes(),tmp.clear()).str());
  100. checker->add("isHost",part->isHost()?1:0);
  101. checker->add("getFileSize",part->getFileSize(false,false));
  102. CDateTime dt;
  103. if (part->getModifiedTime(false,false,dt))
  104. dt.getString(tmp.clear());
  105. else
  106. tmp.clear().append("nodatetime");
  107. checker->add("getModifiedTime",tmp.str());
  108. unsigned crc;
  109. if (part->getCrc(crc)&&!blocked)
  110. checker->add("getCrc",crc);
  111. else
  112. checker->add("getCrc","nocrc");
  113. }
  114. void checkFile(IChecker *checker,IDistributedFile *file)
  115. {
  116. StringBuffer tmp;
  117. checker->add("queryLogicalName",file->queryLogicalName());
  118. unsigned np = file->numParts();
  119. checker->add("numParts",np);
  120. checker->add("queryDefaultDir",file->queryDefaultDir());
  121. if (np>1)
  122. checker->add("queryPartMask",file->queryPartMask());
  123. checker->add("queryProperties()",toXML(&file->queryAttributes(),tmp.clear()).str());
  124. CDateTime dt;
  125. if (file->getModificationTime(dt))
  126. dt.getString(tmp.clear());
  127. else
  128. tmp.clear().append("nodatetime");
  129. // Owned<IFileDescriptor> desc = getFileDescriptor();
  130. // checkFileDescriptor(checker,desc);
  131. //virtual bool existsPhysicalPartFiles(unsigned short port) = 0; // returns true if physical patrs all exist (on primary OR secondary)
  132. //Owned<IPropertyTree> tree = getTreeCopy();
  133. //checker->add("queryProperties()",toXML(tree,tmp.clear()).str());
  134. checker->add("getFileSize",file->getFileSize(false,false));
  135. bool blocked;
  136. checker->add("isCompressed",file->isCompressed(&blocked)?1:0);
  137. checker->add("blocked",blocked?1:0);
  138. unsigned csum;
  139. if (file->getFileCheckSum(csum)&&!blocked)
  140. checker->add("getFileCheckSum",csum);
  141. else
  142. checker->add("getFileCheckSum","nochecksum");
  143. StringBuffer clustname;
  144. checker->add("queryClusterName(0)",file->getClusterName(0,clustname).str());
  145. for (unsigned i=0;i<np;i++) {
  146. Owned<IDistributedFilePart> part = file->getPart(i);
  147. if (part)
  148. checkFilePart(checker,part,blocked);
  149. }
  150. }
  151. void checkFiles(const char *fn)
  152. {
  153. class cChecker: implements IChecker
  154. {
  155. public:
  156. virtual void title(unsigned n,const char *s)
  157. {
  158. printf("Title[%d]='%s'\n",n,s);
  159. }
  160. virtual void add(const char *s,__int64 v)
  161. {
  162. printf("%s=%" I64F "d\n",s,v);
  163. }
  164. virtual void add(const char *s,const char* v)
  165. {
  166. printf("%s='%s'\n",s,v);
  167. }
  168. virtual void add(unsigned n,const char *s,__int64 v)
  169. {
  170. printf("%s[%d]=%" I64F "d\n",s,n,v);
  171. }
  172. virtual void add(unsigned n,const char *s,const char* v)
  173. {
  174. printf("%s[%d]='%s'\n",s,n,v);
  175. }
  176. virtual void error(const char *txt)
  177. {
  178. printf("ERROR '%s'\n",txt);
  179. }
  180. } checker;
  181. unsigned start = msTick();
  182. unsigned slowest = 0;
  183. StringAttr slowname;
  184. if (fn) {
  185. checker.title(1,fn);
  186. try {
  187. Owned<IDistributedFile> file=queryDistributedFileDirectory().lookup(fn,user);
  188. if (!file)
  189. printf("file '%s' not found\n",fn);
  190. else
  191. checkFile(&checker,file);
  192. }
  193. catch (IException *e) {
  194. StringBuffer str;
  195. e->errorMessage(str);
  196. e->Release();
  197. checker.error(str.str());
  198. }
  199. }
  200. else {
  201. Owned<IDistributedFileIterator> iter = queryDistributedFileDirectory().getIterator("*",false,user);
  202. unsigned i=0;
  203. unsigned ss = msTick();
  204. ForEach(*iter) {
  205. i++;
  206. StringBuffer lfname;
  207. iter->getName(lfname);
  208. checker.title(i,lfname.str());
  209. try {
  210. IDistributedFile &file=iter->query();
  211. checkFile(&checker,&file);
  212. unsigned t = (msTick()-ss);
  213. if (t>slowest) {
  214. slowest = t;
  215. slowname.set(lfname.str());
  216. }
  217. }
  218. catch (IException *e) {
  219. StringBuffer str;
  220. e->errorMessage(str);
  221. e->Release();
  222. checker.error(str.str());
  223. }
  224. ss = msTick();
  225. }
  226. }
  227. unsigned t = msTick()-start;
  228. printf("Complete in %ds\n",t/1000);
  229. if (!slowname.isEmpty())
  230. printf("Slowest %s = %dms\n",slowname.get(),slowest);
  231. };
  232. const char *filelist=
  233. "thor_data400::gong_delete_plus,"
  234. "thor_data400::in::npanxx,"
  235. "thor_data400::tpm_deduped,"
  236. "thor_data400::base::movers_ingest_ll,"
  237. "thor_hank::cemtemp::fldl,"
  238. "thor_data400::patch,"
  239. "thor_data400::in::flvehreg_01_prethor_upd200204_v3,"
  240. "thor_data400::in::flvehreg_01_prethor_upd20020625_v3_flag,"
  241. "thor_data400::in::flvehreg_01_prethor_upd20020715_v3,"
  242. "thor_data400::in::flvehreg_01_prethor_upd20020715_v3_v3_flag,"
  243. "thor_data400::in::flvehreg_01_prethor_upd20020816_v3,"
  244. "thor_data400::in::flvehreg_01_prethor_upd20020816_v3_flag,"
  245. "thor_data400::in::flvehreg_01_prethor_upd20020625_v3,"
  246. "thor_data400::in::fl_lic_prethor_200208v2,"
  247. "thor_data400::in::fl_lic_prethor_200209,"
  248. "thor_data400::in::fl_lic_prethor_200210,"
  249. "thor_data400::in::fl_lic_prethor_200210_reclean,"
  250. "thor_data400::in::fl_lic_upd_200301,"
  251. "thor_data400::in::fl_lic_upd_200302,"
  252. "thor_data400::in::oh_lic_200209,"
  253. "thor_data400::in::ohio_lic_upd_200210,"
  254. "thor_data400::prepped_for_keys,"
  255. "a0e65__w20060224-155748,"
  256. "common_did,"
  257. "test::ftest1,"
  258. "thor_data50::BASE::chunk,"
  259. "hthor::key::codes_v320040901,"
  260. "thor_data400::in::ucc_direct_ok_99999999_event_20060124,"
  261. "thor400::ks_work::distancedetails";
  262. #ifndef COMPAT
  263. void dispFDesc(IFileDescriptor *fdesc)
  264. {
  265. printf("======================================\n");
  266. Owned<IPropertyTree> pt = createPTree("File");
  267. fdesc->serializeTree(*pt);
  268. StringBuffer out;
  269. toXML(pt,out);
  270. printf("%s\n",out.str());
  271. Owned<IFileDescriptor> fdesc2 = deserializeFileDescriptorTree(pt);
  272. toXML(pt,out.clear());
  273. printf("%s\n",out.str());
  274. unsigned np = fdesc->numParts();
  275. unsigned ncl = fdesc->numClusters();
  276. printf("numclusters = %d, numparts=%d\n",ncl,np);
  277. for (unsigned pass=0;pass<1;pass++) {
  278. for (unsigned ip=0;ip<np;ip++) {
  279. IPartDescriptor *part = fdesc->queryPart(ip);
  280. unsigned nc = part->numCopies();
  281. for (unsigned ic=0;ic<nc;ic++) {
  282. StringBuffer tmp1;
  283. StringBuffer tmp2;
  284. StringBuffer tmp3;
  285. StringBuffer tmp4;
  286. RemoteFilename rfn;
  287. bool blocked;
  288. out.clear().appendf("%d,%d: '%s' '%s' '%s' '%s' '%s' '%s' %s%s%s",ip,ic,
  289. part->getDirectory(tmp1,ic).str(),
  290. part->getTail(tmp2).str(),
  291. part->getPath(tmp3,ic).str(),
  292. fdesc->getFilename(ip,ic,rfn).getRemotePath(tmp4).str(), // multi TBD
  293. fdesc->queryPartMask()?fdesc->queryPartMask():"",
  294. fdesc->queryDefaultDir()?fdesc->queryDefaultDir():"",
  295. fdesc->isGrouped()?"GROUPED ":"",
  296. fdesc->queryKind()?fdesc->queryKind():"",
  297. fdesc->isCompressed(&blocked)?(blocked?" BLOCKCOMPRESSED":" COMPRESSED"):""
  298. );
  299. printf("%s\n",out.str());
  300. if (1) {
  301. MemoryBuffer mb;
  302. part->serialize(mb);
  303. Owned<IPartDescriptor> copypart;
  304. copypart.setown(deserializePartFileDescriptor(mb));
  305. StringBuffer out2;
  306. out2.appendf("%d,%d: '%s' '%s' '%s' '%s' '%s' '%s' %s%s%s",ip,ic,
  307. copypart->getDirectory(tmp1.clear(),ic).str(),
  308. copypart->getTail(tmp2.clear()).str(),
  309. copypart->getPath(tmp3.clear(),ic).str(),
  310. copypart->getFilename(ic,rfn).getRemotePath(tmp4.clear()).str(), // multi TBD
  311. copypart->queryOwner().queryPartMask()?copypart->queryOwner().queryPartMask():"",
  312. copypart->queryOwner().queryDefaultDir()?copypart->queryOwner().queryDefaultDir():"",
  313. copypart->queryOwner().isGrouped()?"GROUPED ":"",
  314. copypart->queryOwner().queryKind()?copypart->queryOwner().queryKind():"",
  315. copypart->queryOwner().isCompressed(&blocked)?(blocked?" BLOCKCOMPRESSED":" COMPRESSED"):""
  316. );
  317. if (strcmp(out.str(),out2.str())!=0)
  318. printf("FAILED!\n%s\n%s\n",out.str(),out2.str());
  319. pt.setown(createPTree("File"));
  320. copypart->queryOwner().serializeTree(*pt);
  321. StringBuffer out;
  322. toXML(pt,out);
  323. // printf("%d,%d: \n%s\n",ip,ic,out.str());
  324. }
  325. }
  326. }
  327. }
  328. }
  329. #endif
  330. // ================================================================================== UNIT TESTS
  331. class CDaliTestsStress : public CppUnit::TestFixture
  332. {
  333. CPPUNIT_TEST_SUITE(CDaliTestsStress);
  334. CPPUNIT_TEST(testInit);
  335. CPPUNIT_TEST(testDFS);
  336. // CPPUNIT_TEST(testReadAllSDS); // Ignoring this test; See comments below
  337. CPPUNIT_TEST(testFiles);
  338. #ifndef COMPAT
  339. CPPUNIT_TEST(testDF1);
  340. CPPUNIT_TEST(testDF2);
  341. CPPUNIT_TEST(testMisc);
  342. CPPUNIT_TEST(testDFile);
  343. #endif
  344. CPPUNIT_TEST_SUITE_END();
  345. const IContextLogger &logctx;
  346. public:
  347. CDaliTestsStress() : logctx(queryDummyContextLogger())
  348. {
  349. }
  350. ~CDaliTestsStress()
  351. {
  352. daliClientEnd();
  353. }
  354. void testInit()
  355. {
  356. daliClientInit();
  357. }
  358. #ifndef COMPAT
  359. void testDF1()
  360. {
  361. const char * fname = "testing::propfile2";
  362. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  363. Owned<IPropertyTree> pt = createPTree("Attr");
  364. RemoteFilename rfn;
  365. rfn.setRemotePath("//10.150.10.80/c$/thordata/test/part._1_of_3");
  366. pt->setPropInt("@size",123);
  367. fdesc->setPart(0,rfn,pt);
  368. rfn.setRemotePath("//10.150.10.81/c$/thordata/test/part._2_of_3");
  369. pt->setPropInt("@size",456);
  370. fdesc->setPart(1,rfn,pt);
  371. rfn.setRemotePath("//10.150.10.82/c$/thordata/test/part._3_of_3");
  372. pt->setPropInt("@size",789);
  373. fdesc->setPart(2,rfn,pt);
  374. dispFDesc(fdesc);
  375. try {
  376. removeLogical(fname, user);
  377. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  378. {
  379. DistributedFilePropertyLock lock(file);
  380. lock.queryAttributes().setProp("@testing","1");
  381. }
  382. file->attach(fname,user);
  383. } catch (IException *e) {
  384. StringBuffer msg;
  385. e->errorMessage(msg);
  386. logctx.CTXLOG("Caught exception while setting property: %s", msg.str());
  387. e->Release();
  388. }
  389. }
  390. void testDF2() // 4*3 superfile
  391. {
  392. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  393. Owned<IPropertyTree> pt = createPTree("Attr");
  394. RemoteFilename rfn;
  395. rfn.setRemotePath("//10.150.10.80/c$/thordata/test/partone._1_of_3");
  396. pt->setPropInt("@size",1231);
  397. fdesc->setPart(0,rfn,pt);
  398. rfn.setRemotePath("//10.150.10.80/c$/thordata/test/parttwo._1_of_3");
  399. pt->setPropInt("@size",1232);
  400. fdesc->setPart(1,rfn,pt);
  401. rfn.setRemotePath("//10.150.10.80/c$/thordata/test/partthree._1_of_3");
  402. pt->setPropInt("@size",1233);
  403. fdesc->setPart(2,rfn,pt);
  404. rfn.setRemotePath("//10.150.10.80/c$/thordata/test2/partfour._1_of_3");
  405. pt->setPropInt("@size",1234);
  406. fdesc->setPart(3,rfn,pt);
  407. rfn.setRemotePath("//10.150.10.81/c$/thordata/test/partone._2_of_3");
  408. pt->setPropInt("@size",4565);
  409. fdesc->setPart(4,rfn,pt);
  410. rfn.setRemotePath("//10.150.10.81/c$/thordata/test/parttwo._2_of_3");
  411. pt->setPropInt("@size",4566);
  412. fdesc->setPart(5,rfn,pt);
  413. rfn.setRemotePath("//10.150.10.81/c$/thordata/test/partthree._2_of_3");
  414. pt->setPropInt("@size",4567);
  415. fdesc->setPart(6,rfn,pt);
  416. rfn.setRemotePath("//10.150.10.81/c$/thordata/test2/partfour._2_of_3");
  417. pt->setPropInt("@size",4568);
  418. fdesc->setPart(7,rfn,pt);
  419. rfn.setRemotePath("//10.150.10.82/c$/thordata/test/partone._3_of_3");
  420. pt->setPropInt("@size",7899);
  421. fdesc->setPart(8,rfn,pt);
  422. rfn.setRemotePath("//10.150.10.82/c$/thordata/test/parttwo._3_of_3");
  423. pt->setPropInt("@size",78910);
  424. fdesc->setPart(9,rfn,pt);
  425. rfn.setRemotePath("//10.150.10.82/c$/thordata/test/partthree._3_of_3");
  426. pt->setPropInt("@size",78911);
  427. fdesc->setPart(10,rfn,pt);
  428. rfn.setRemotePath("//10.150.10.82/c$/thordata/test2/partfour._3_of_3");
  429. pt->setPropInt("@size",78912);
  430. fdesc->setPart(11,rfn,pt);
  431. ClusterPartDiskMapSpec mspec;
  432. mspec.interleave = 4;
  433. fdesc->endCluster(mspec);
  434. dispFDesc(fdesc);
  435. }
  436. void testMisc()
  437. {
  438. ClusterPartDiskMapSpec mspec;
  439. Owned<IGroup> grp = createIGroup("10.150.10.1-3");
  440. RemoteFilename rfn;
  441. for (unsigned i=0;i<3;i++)
  442. for (unsigned ic=0;ic<mspec.defaultCopies;ic++) {
  443. constructPartFilename(grp,i+1,3,(i==1)?"test.txt":NULL,"test._$P$_of_$N$","/c$/thordata/test",ic,mspec,rfn);
  444. StringBuffer tmp;
  445. printf("%d,%d: %s\n",i,ic,rfn.getRemotePath(tmp).str());
  446. }
  447. }
  448. void testDFile()
  449. {
  450. ClusterPartDiskMapSpec map;
  451. { // 1: single part file old method
  452. #define TN "1"
  453. removeLogical("test::ftest" TN, user);
  454. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  455. RemoteFilename rfn;
  456. rfn.setRemotePath("//10.150.10.1/c$/thordata/test/ftest" TN "._1_of_1");
  457. fdesc->setPart(0,rfn);
  458. fdesc->endCluster(map);
  459. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  460. file->attach("test::ftest" TN,user);
  461. #undef TN
  462. }
  463. { // 2: single part file new method
  464. #define TN "2"
  465. removeLogical("test::ftest" TN, user);
  466. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  467. fdesc->setPartMask("ftest" TN "._$P$_of_$N$");
  468. fdesc->setNumParts(1);
  469. Owned<IGroup> grp = createIGroup("10.150.10.1");
  470. fdesc->addCluster(grp,map);
  471. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  472. file->attach("test::ftest" TN,user);
  473. #undef TN
  474. }
  475. Owned<IGroup> grp3 = createIGroup("10.150.10.1,10.150.10.2,10.150.10.3");
  476. queryNamedGroupStore().add("__testgroup3__",grp3,true);
  477. { // 3: three parts file old method
  478. #define TN "3"
  479. removeLogical("test::ftest" TN, user);
  480. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  481. RemoteFilename rfn;
  482. rfn.setRemotePath("//10.150.10.1/c$/thordata/test/ftest" TN "._1_of_3");
  483. fdesc->setPart(0,rfn);
  484. rfn.setRemotePath("//10.150.10.2/c$/thordata/test/ftest" TN "._2_of_3");
  485. fdesc->setPart(1,rfn);
  486. rfn.setRemotePath("//10.150.10.3/c$/thordata/test/ftest" TN "._3_of_3");
  487. fdesc->setPart(2,rfn);
  488. fdesc->endCluster(map);
  489. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  490. file->attach("test::ftest" TN,user);
  491. #undef TN
  492. }
  493. { // 4: three part file new method
  494. #define TN "4"
  495. removeLogical("test::ftest" TN, user);
  496. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  497. fdesc->setPartMask("ftest" TN "._$P$_of_$N$");
  498. fdesc->setNumParts(3);
  499. fdesc->addCluster(grp3,map);
  500. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  501. file->attach("test::ftest" TN,user);
  502. #undef TN
  503. }
  504. }
  505. #endif
  506. /*
  507. * This test is invasive, obsolete and the main source of
  508. * errors in the DFS code. It was created on a time where
  509. * the DFS API was spread open and methods could openly
  510. * fiddle with its internals without injury. Times have changed.
  511. *
  512. * TODO: Convert this test into a proper test of the DFS as
  513. * it currently stands, not work around its deficiencies.
  514. *
  515. * Unfortunately, to do that, some functionality has to be
  516. * re-worked (like creating groups, adding files to it,
  517. * creating physical temporary files, etc).
  518. */
  519. void testDFS()
  520. {
  521. const size32_t recsize = 17;
  522. StringBuffer s;
  523. unsigned i;
  524. unsigned n;
  525. unsigned t;
  526. queryNamedGroupStore().remove("daregress_group");
  527. dir.removeEntry("daregress::superfile1", user);
  528. SocketEndpointArray epa;
  529. for (n=0;n<400;n++) {
  530. s.clear().append("192.168.").append(n/256).append('.').append(n%256);
  531. SocketEndpoint ep(s.str());
  532. epa.append(ep);
  533. }
  534. Owned<IGroup> group = createIGroup(epa);
  535. queryNamedGroupStore().add("daregress_group",group,true);
  536. ASSERT(queryNamedGroupStore().find(group,s.clear()) && "Created logical group not found");
  537. ASSERT(stricmp(s.str(),"daregress_group")==0 && "Created logical group found with wrong name");
  538. group.setown(queryNamedGroupStore().lookup("daregress_group"));
  539. ASSERT(group && "named group lookup failed");
  540. logctx.CTXLOG("Named group created - 400 nodes");
  541. for (i=0;i<100;i++) {
  542. Owned<IPropertyTree> pp = createPTree("Part");
  543. Owned<IFileDescriptor>fdesc = createFileDescriptor();
  544. fdesc->setDefaultDir("thordata/regress");
  545. n = 9;
  546. for (unsigned k=0;k<400;k++) {
  547. s.clear().append("192.168.").append(n/256).append('.').append(n%256);
  548. Owned<INode> node = createINode(s.str());
  549. pp->setPropInt64("@size",(n*777+i)*recsize);
  550. s.clear().append("daregress_test").append(i).append("._").append(n+1).append("_of_400");
  551. fdesc->setPart(n,node,s.str(),pp);
  552. n = (n+9)%400;
  553. }
  554. fdesc->queryProperties().setPropInt("@recordSize",17);
  555. s.clear().append("daregress::test").append(i);
  556. removeLogical(s.str(), user);
  557. StringBuffer cname;
  558. Owned<IDistributedFile> dfile = dir.createNew(fdesc);
  559. ASSERT(stricmp(dfile->getClusterName(0,cname),"daregress_group")==0 && "Cluster name wrong");
  560. s.clear().append("daregress::test").append(i);
  561. dfile->attach(s.str(),user);
  562. }
  563. logctx.CTXLOG("DFile create done - 100 files");
  564. unsigned samples = 5;
  565. t = 33;
  566. for (i=0;i<100;i++) {
  567. s.clear().append("daregress::test").append(t);
  568. ASSERT(dir.exists(s.str(),user) && "Could not find sub-file");
  569. Owned<IDistributedFile> dfile = dir.lookup(s.str(), user);
  570. ASSERT(dfile && "Could not find sub-file");
  571. offset_t totsz = 0;
  572. n = 11;
  573. for (unsigned k=0;k<400;k++) {
  574. Owned<IDistributedFilePart> part = dfile->getPart(n);
  575. ASSERT(part && "part not found");
  576. s.clear().append("192.168.").append(n/256).append('.').append(n%256);
  577. Owned<INode> node = createINode(s.str());
  578. ASSERT(node->equals(part->queryNode()) && "part node mismatch");
  579. ASSERT(part->getFileSize(false,false)==(n*777+t)*recsize && "size node mismatch");
  580. s.clear().append("daregress_test").append(t).append("._").append(n+1).append("_of_400");
  581. /* ** TBD
  582. if (stricmp(s.str(),part->queryPartName())!=0)
  583. ERROR4("part name mismatch %d, %d '%s' '%s'",t,n,s.str(),part->queryPartName());
  584. */
  585. totsz += (n*777+t)*recsize;
  586. if ((samples>0)&&(i+n+t==k)) {
  587. samples--;
  588. RemoteFilename rfn;
  589. part->getFilename(rfn,samples%2);
  590. StringBuffer fn;
  591. rfn.getRemotePath(fn);
  592. logctx.CTXLOG("SAMPLE: %d,%d %s",t,n,fn.str());
  593. }
  594. n = (n+11)%400;
  595. }
  596. ASSERT(totsz==dfile->getFileSize(false,false) && "total size mismatch");
  597. t = (t+33)%100;
  598. }
  599. logctx.CTXLOG("DFile lookup done - 100 files");
  600. // check iteration
  601. __int64 crctot = 0;
  602. unsigned np = 0;
  603. unsigned totrows = 0;
  604. Owned<IDistributedFileIterator> fiter = dir.getIterator("daregress::*",false, user);
  605. Owned<IDistributedFilePartIterator> piter;
  606. ForEach(*fiter) {
  607. piter.setown(fiter->query().getIterator());
  608. ForEach(*piter) {
  609. RemoteFilename rfn;
  610. StringBuffer s;
  611. piter->query().getFilename(rfn,0);
  612. rfn.getRemotePath(s);
  613. piter->query().getFilename(rfn,1);
  614. rfn.getRemotePath(s);
  615. crctot += crc32(s.str(),s.length(),0);
  616. np++;
  617. totrows += (unsigned)(piter->query().getFileSize(false,false)/fiter->query().queryAttributes().getPropInt("@recordSize",-1));
  618. }
  619. }
  620. piter.clear();
  621. fiter.clear();
  622. logctx.CTXLOG("DFile iterate done - %d parts, %d rows, CRC sum %" I64F "d",np,totrows,crctot);
  623. Owned<IDistributedSuperFile> sfile;
  624. sfile.setown(dir.createSuperFile("daregress::superfile1",user,true,false));
  625. for (i = 0;i<100;i++) {
  626. s.clear().append("daregress::test").append(i);
  627. sfile->addSubFile(s.str());
  628. }
  629. sfile.clear();
  630. sfile.setown(dir.lookupSuperFile("daregress::superfile1", user));
  631. ASSERT(sfile && "Could not find added superfile");
  632. __int64 savcrc = crctot;
  633. crctot = 0;
  634. np = 0;
  635. totrows = 0;
  636. size32_t srs = (size32_t)sfile->queryAttributes().getPropInt("@recordSize",-1);
  637. ASSERT(srs==17 && "Superfile does not match subfile row size");
  638. piter.setown(sfile->getIterator());
  639. ForEach(*piter) {
  640. RemoteFilename rfn;
  641. StringBuffer s;
  642. piter->query().getFilename(rfn,0);
  643. rfn.getRemotePath(s);
  644. piter->query().getFilename(rfn,1);
  645. rfn.getRemotePath(s);
  646. crctot += crc32(s.str(),s.length(),0);
  647. np++;
  648. totrows += (unsigned)(piter->query().getFileSize(false,false)/srs);
  649. }
  650. piter.clear();
  651. logctx.CTXLOG("Superfile iterate done - %d parts, %d rows, CRC sum %" I64F "d",np,totrows,crctot);
  652. ASSERT(crctot==savcrc && "SuperFile does not match sub files");
  653. unsigned tr = (unsigned)(sfile->getFileSize(false,false)/srs);
  654. ASSERT(totrows==tr && "Superfile size does not match part sum");
  655. sfile->detach();
  656. sfile.clear();
  657. sfile.setown(dir.lookupSuperFile("daregress::superfile1",user));
  658. ASSERT(!sfile && "Superfile deletion failed");
  659. t = 37;
  660. for (i=0;i<100;i++) {
  661. s.clear().append("daregress::test").append(t);
  662. removeLogical(s.str(), user);
  663. t = (t+37)%100;
  664. }
  665. logctx.CTXLOG("DFile removal complete");
  666. t = 39;
  667. for (i=0;i<100;i++) {
  668. ASSERT(!dir.exists(s.str(),user) && "Found dir after deletion");
  669. Owned<IDistributedFile> dfile = dir.lookup(s.str(), user);
  670. ASSERT(!dfile && "Found file after deletion");
  671. t = (t+39)%100;
  672. }
  673. logctx.CTXLOG("DFile removal check complete");
  674. queryNamedGroupStore().remove("daregress_group");
  675. ASSERT(!queryNamedGroupStore().lookup("daregress_group") && "Named group not removed");
  676. }
  677. void testFiles()
  678. {
  679. StringBuffer fn;
  680. const char *s = filelist;
  681. unsigned slowest = 0;
  682. StringAttr slowname;
  683. unsigned tot = 0;
  684. unsigned n = 0;
  685. while (*s) {
  686. fn.clear();
  687. while (*s==',')
  688. s++;
  689. while (*s&&(*s!=','))
  690. fn.append(*(s++));
  691. if (fn.length()) {
  692. n++;
  693. unsigned ss = msTick();
  694. checkFiles(fn);
  695. unsigned t = (msTick()-ss);
  696. if (t>slowest) {
  697. slowest = t;
  698. slowname.set(fn);
  699. }
  700. tot += t;
  701. }
  702. }
  703. printf("Complete in %ds avg %dms\n",tot/1000,tot/(n?n:1));
  704. if (!slowname.isEmpty())
  705. printf("Slowest %s = %dms\n",slowname.get(),slowest);
  706. }
  707. void testReadBranch(const char *path)
  708. {
  709. PROGLOG("Connecting to %s",path);
  710. Owned<IRemoteConnection> conn = querySDS().connect(path, myProcessSession(), RTM_LOCK_READ, 10000);
  711. ASSERT(conn && "Could not connect");
  712. IPropertyTree *root = conn->queryRoot();
  713. Owned<IAttributeIterator> aiter = root->getAttributes();
  714. StringBuffer s;
  715. ForEach(*aiter)
  716. aiter->getValue(s.clear());
  717. aiter.clear();
  718. root->getProp(NULL,s.clear());
  719. Owned<IPropertyTreeIterator> iter = root->getElements("*");
  720. StringAttrArray children;
  721. UnsignedArray childidx;
  722. ForEach(*iter) {
  723. children.append(*new StringAttrItem(iter->query().queryName()));
  724. childidx.append(root->queryChildIndex(&iter->query()));
  725. }
  726. iter.clear();
  727. conn.clear();
  728. ForEachItemIn(i,children) {
  729. s.clear().append(path);
  730. if (path[strlen(path)-1]!='/')
  731. s.append('/');
  732. s.append(children.item(i).text).append('[').append(childidx.item(i)+1).append(']');
  733. testReadBranch(s.str());
  734. }
  735. }
  736. /*
  737. * This test is silly and can take a very long time on clusters with
  738. * a large file-system. But keeping it here for further reference.
  739. * MORE: Maybe, this could be added to daliadmin or a thorough check
  740. * on the filesystem, together with super-file checks et al.
  741. void testReadAllSDS()
  742. {
  743. logctx.CTXLOG("Test SDS connecting to every branch");
  744. testReadBranch("/");
  745. logctx.CTXLOG("Connected to every branch");
  746. }
  747. */
  748. };
  749. CPPUNIT_TEST_SUITE_REGISTRATION( CDaliTestsStress );
  750. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliTestsStress, "CDaliTestsStress" );
  751. // ================================================================================== UNIT TESTS
  752. class CDaliSDSTests : public CppUnit::TestFixture
  753. {
  754. CPPUNIT_TEST_SUITE(CDaliSDSTests);
  755. CPPUNIT_TEST(testInit);
  756. CPPUNIT_TEST(testSDSRW);
  757. CPPUNIT_TEST(testSDSSubs);
  758. CPPUNIT_TEST(testSDSSubs2);
  759. CPPUNIT_TEST(testSDSNodeSubs);
  760. CPPUNIT_TEST_SUITE_END();
  761. const IContextLogger &logctx;
  762. static const unsigned numCChangeTests = 1;
  763. static const unsigned subsPerCChange = 10;
  764. static const unsigned numCChangeCommits = 10;
  765. void sdsNodeCommit(const char *test, unsigned from, unsigned to, bool finalDelete)
  766. {
  767. class CNodeSubCommitThread : public CInterface, implements IThreaded
  768. {
  769. StringAttr xpath;
  770. bool finalDelete;
  771. CThreaded threaded;
  772. public:
  773. IMPLEMENT_IINTERFACE;
  774. CNodeSubCommitThread(const char *_xpath, bool _finalDelete) : threaded("CNodeSubCommitThread"), xpath(_xpath), finalDelete(_finalDelete)
  775. {
  776. }
  777. virtual void threadmain() override
  778. {
  779. unsigned mode = RTM_LOCK_WRITE;
  780. if (finalDelete)
  781. mode |= RTM_DELETE_ON_DISCONNECT;
  782. Owned<IRemoteConnection> conn = querySDS().connect(xpath, myProcessSession(), mode, 1000000);
  783. assertex(conn);
  784. for (unsigned i=0; i<5; i++)
  785. {
  786. VStringBuffer val("newval%d", i+1);
  787. conn->queryRoot()->setProp(NULL, val.str());
  788. conn->commit();
  789. }
  790. conn->queryRoot()->setProp("subnode", "newval");
  791. conn->commit();
  792. conn.clear(); // if finalDelete=true, deletes subscribed node in process, should get notificaiton
  793. }
  794. void start()
  795. {
  796. threaded.init(this);
  797. }
  798. void join()
  799. {
  800. threaded.join();
  801. }
  802. };
  803. CIArrayOf<CNodeSubCommitThread> commitThreads;
  804. for (unsigned i=from; i<=to; i++)
  805. {
  806. VStringBuffer path("/DAREGRESS/NodeSubTest/node%d", i);
  807. CNodeSubCommitThread *commitThread = new CNodeSubCommitThread(path, finalDelete);
  808. commitThreads.append(* commitThread);
  809. }
  810. ForEachItemIn(t, commitThreads)
  811. commitThreads.item(t).start();
  812. ForEachItemIn(t2, commitThreads)
  813. commitThreads.item(t2).join();
  814. }
  815. unsigned fn(unsigned n, unsigned m, unsigned seed, unsigned depth, IPropertyTree *parent)
  816. {
  817. __int64 val = parent->getPropInt64("val",0);
  818. parent->setPropInt64("val",n+val);
  819. val = parent->getPropInt64("@val",0);
  820. parent->setPropInt64("@val",m+val);
  821. val = parent->getPropInt64(NULL,0);
  822. parent->setPropInt64(NULL,seed+val);
  823. if (Rconn&&((n+m+seed)%100==0))
  824. Rconn->commit();
  825. if (!seed)
  826. return m+n;
  827. if (n==m)
  828. return seed;
  829. if (depth>10)
  830. return seed+n+m;
  831. if (seed%7==n%7)
  832. return n;
  833. if (seed%7==m%7)
  834. return m;
  835. char name[64];
  836. unsigned v = seed;
  837. name[0] = 's';
  838. name[1] = 'u';
  839. name[2] = 'b';
  840. unsigned i = 3;
  841. while (v) {
  842. name[i++] = ('A'+v%26 );
  843. v /= 26;
  844. }
  845. name[i] = 0;
  846. IPropertyTree *child = parent->queryPropTree(name);
  847. if (!child)
  848. child = parent->addPropTree(name, createPTree(name));
  849. return fn(fn(n,seed,seed*17+11,depth+1,child),fn(seed,m,seed*11+17,depth+1,child),seed*19+7,depth+1,child);
  850. }
  851. unsigned fn2(unsigned n, unsigned m, unsigned seed, unsigned depth, StringBuffer &parentname)
  852. {
  853. if (!Rconn)
  854. return 0;
  855. if ((n+m+seed)%25==0) {
  856. Rconn->commit();
  857. Rconn->Release();
  858. Rconn = querySDS().connect("/DAREGRESS",myProcessSession(), 0, 1000000);
  859. ASSERT(Rconn && "Failed to connect to /DAREGRESS");
  860. }
  861. IPropertyTree *parent = parentname.length()?Rconn->queryRoot()->queryPropTree(parentname.str()):Rconn->queryRoot();
  862. ASSERT(parent && "Failed to connect to parent");
  863. __int64 val = parent->getPropInt64("val",0);
  864. parent->setPropInt64("val",n+val);
  865. val = parent->getPropInt64("@val",0);
  866. parent->setPropInt64("@val",m+val);
  867. val = parent->getPropInt64(NULL,0);
  868. parent->setPropInt64(NULL,seed+val);
  869. if (!seed)
  870. return m+n;
  871. if (n==m)
  872. return seed;
  873. if (depth>10)
  874. return seed+n+m;
  875. if (seed%7==n%7)
  876. return n;
  877. if (seed%7==m%7)
  878. return m;
  879. char name[64];
  880. unsigned v = seed;
  881. name[0] = 's';
  882. name[1] = 'u';
  883. name[2] = 'b';
  884. unsigned i = 3;
  885. while (v) {
  886. name[i++] = ('A'+v%26 );
  887. v /= 26;
  888. }
  889. name[i] = 0;
  890. unsigned l = parentname.length();
  891. if (parentname.length())
  892. parentname.append('/');
  893. parentname.append(name);
  894. IPropertyTree *child = parent->queryPropTree(name);
  895. if (!child)
  896. child = parent->addPropTree(name, createPTree(name));
  897. unsigned ret = fn2(fn2(n,seed,seed*17+11,depth+1,parentname),fn2(seed,m,seed*11+17,depth+1,parentname),seed*19+7,depth+1,parentname);
  898. parentname.setLength(l);
  899. return ret;
  900. }
  901. public:
  902. CDaliSDSTests() : logctx(queryDummyContextLogger())
  903. {
  904. }
  905. ~CDaliSDSTests()
  906. {
  907. daliClientEnd();
  908. }
  909. void testInit()
  910. {
  911. daliClientInit();
  912. }
  913. void testSDSRW()
  914. {
  915. Owned<IPropertyTree> ref = createPTree("DAREGRESS");
  916. fn(1,2,3,0,ref);
  917. StringBuffer refstr;
  918. toXML(ref,refstr,0,XML_SortTags|XML_Format);
  919. logctx.CTXLOG("Created reference size %d",refstr.length());
  920. Owned<IRemoteConnection> conn = querySDS().connect("/DAREGRESS",myProcessSession(), RTM_CREATE, 1000000);
  921. Rconn = conn;
  922. IPropertyTree *root = conn->queryRoot();
  923. fn(1,2,3,0,root);
  924. conn.clear();
  925. logctx.CTXLOG("Created test branch 1");
  926. conn.setown(querySDS().connect("/DAREGRESS",myProcessSession(), RTM_DELETE_ON_DISCONNECT, 1000000));
  927. root = conn->queryRoot();
  928. StringBuffer s;
  929. toXML(root,s,0,XML_SortTags|XML_Format);
  930. ASSERT(strcmp(s.str(),refstr.str())==0 && "Branch 1 does not match");
  931. conn.clear();
  932. conn.setown(querySDS().connect("/DAREGRESS",myProcessSession(), 0, 1000000));
  933. ASSERT(!conn && "RTM_DELETE_ON_DISCONNECT failed");
  934. Rconn = querySDS().connect("/DAREGRESS",myProcessSession(), RTM_CREATE, 1000000);
  935. StringBuffer pn;
  936. fn2(1,2,3,0,pn);
  937. ::Release(Rconn);
  938. logctx.CTXLOG("Created test branch 2");
  939. Rconn = NULL;
  940. conn.setown(querySDS().connect("/DAREGRESS",myProcessSession(), RTM_DELETE_ON_DISCONNECT, 1000000));
  941. root = conn->queryRoot();
  942. toXML(root,s.clear(),0,XML_SortTags|XML_Format);
  943. ASSERT(strcmp(s.str(),refstr.str())==0 && "Branch 2 does not match");
  944. conn.clear();
  945. conn.setown(querySDS().connect("/DAREGRESS",myProcessSession(), 0, 1000000));
  946. ASSERT(!conn && "RTM_DELETE_ON_DISCONNECT failed");
  947. }
  948. void testSDSSubs()
  949. {
  950. class CChange : public Thread
  951. {
  952. class CCSub : public CInterface, implements ISDSConnectionSubscription, implements ISDSSubscription
  953. {
  954. unsigned n;
  955. unsigned &count;
  956. public:
  957. IMPLEMENT_IINTERFACE;
  958. CCSub(unsigned _n,unsigned &_count)
  959. : count(_count)
  960. {
  961. n = _n;
  962. }
  963. virtual void notify()
  964. {
  965. CriticalBlock block(subchangesect);
  966. subchangetotal += n;
  967. subchangenum++;
  968. count++;
  969. }
  970. virtual void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  971. {
  972. CriticalBlock block(subchangesect);
  973. subchangetotal += n;
  974. subchangenum++;
  975. subchangetotal += (unsigned)flags;
  976. subchangetotal += crc32(xpath,strlen(xpath),0);
  977. if (valueLen)
  978. subchangetotal += crc32((const char *)valueData,valueLen,0);
  979. count++;
  980. }
  981. };
  982. Owned<IRemoteConnection> conn;
  983. StringAttr path;
  984. SubscriptionId id[10];
  985. unsigned n;
  986. unsigned count;
  987. public:
  988. Semaphore stopsem;
  989. CChange(unsigned _n)
  990. {
  991. n = _n;
  992. StringBuffer s("/DAREGRESS/CONSUB");
  993. s.append(n+1);
  994. path.set(s.str());
  995. conn.setown(querySDS().connect(path, myProcessSession(), RTM_CREATE|RTM_DELETE_ON_DISCONNECT, 1000000));
  996. unsigned i;
  997. for (i=0;i<subsPerCChange/2;i++)
  998. {
  999. Owned<CCSub> sub = new CCSub(n*subsPerCChange+i,count);
  1000. id[i] = conn->subscribe(*sub);
  1001. }
  1002. s.append("/testprop");
  1003. for (;i<subsPerCChange;i++)
  1004. {
  1005. Owned<CCSub> sub = new CCSub(n*subsPerCChange+i,count);
  1006. id[i] = querySDS().subscribe(s.str(),*sub,false,true);
  1007. }
  1008. count = 0;
  1009. start();
  1010. }
  1011. virtual int run()
  1012. {
  1013. unsigned i;
  1014. for (i = 0;i<numCChangeCommits; i++) {
  1015. conn->queryRoot()->setPropInt("testprop", (i*17+n*21)%100);
  1016. conn->commit();
  1017. for (unsigned j=0;j<1000;j++) {
  1018. {
  1019. CriticalBlock block(subchangesect);
  1020. if (count>=(i+1)*10)
  1021. break;
  1022. }
  1023. Sleep(10);
  1024. }
  1025. }
  1026. stopsem.wait();
  1027. for (i=0;i<subsPerCChange/2;i++)
  1028. conn->unsubscribe(id[i]);
  1029. for (;i<subsPerCChange;i++)
  1030. querySDS().unsubscribe(id[i]);
  1031. return 0;
  1032. }
  1033. };
  1034. subchangenum = 0;
  1035. subchangetotal = 0;
  1036. IArrayOf<CChange> a;
  1037. for (unsigned i=0; i<numCChangeTests ; i++)
  1038. a.append(*new CChange(i));
  1039. unsigned last = 0;
  1040. for (;;)
  1041. {
  1042. Sleep(1000);
  1043. {
  1044. CriticalBlock block(subchangesect);
  1045. if (subchangenum==last)
  1046. break;
  1047. last = subchangenum;
  1048. }
  1049. }
  1050. ForEachItemIn(i1, a)
  1051. a.item(i1).stopsem.signal();
  1052. ForEachItemIn(i2, a)
  1053. a.item(i2).join();
  1054. logctx.CTXLOG("%d subscription notifications, check sum = %" I64F "d",subchangenum,subchangetotal);
  1055. ASSERT(subchangenum==( numCChangeTests * subsPerCChange * numCChangeCommits) && "Not all notifications received");
  1056. }
  1057. void testSDSSubs2()
  1058. {
  1059. class CSubscriberContainer : public CInterface
  1060. {
  1061. class CSubscriber : public CSimpleInterfaceOf<ISDSSubscription>
  1062. {
  1063. StringAttr xpath;
  1064. bool sub;
  1065. StringBuffer &result;
  1066. public:
  1067. CSubscriber(StringBuffer &_result, const char *_xpath, bool _sub) : result(_result), xpath(_xpath), sub(_sub)
  1068. {
  1069. }
  1070. virtual void notify(SubscriptionId id, const char *_xpath, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  1071. {
  1072. PROGLOG("CSubscriber notified path=%s for subscriber=%s, sub=%s", _xpath, xpath.get(), sub?"true":"false");
  1073. if (result.length())
  1074. result.append("|");
  1075. result.append(xpath);
  1076. if (!sub && valueLen)
  1077. result.append(",").append(valueLen, (const char *)valueData);
  1078. }
  1079. };
  1080. Owned<CSubscriber> subscriber;
  1081. SubscriptionId id;
  1082. public:
  1083. CSubscriberContainer(StringBuffer &result, const char *xpath, bool sub)
  1084. {
  1085. subscriber.setown(new CSubscriber(result, xpath, sub));
  1086. id = querySDS().subscribe(xpath, *subscriber, sub, !sub);
  1087. PROGLOG("Subscribed to %s", xpath);
  1088. }
  1089. virtual void beforeDispose() override
  1090. {
  1091. querySDS().unsubscribe(id);
  1092. }
  1093. };
  1094. Owned<IRemoteConnection> conn = querySDS().connect("/", myProcessSession(), RTM_LOCK_WRITE, INFINITE);
  1095. IPropertyTree *root = conn->queryRoot();
  1096. IPropertyTree *daRegress = root->setPropTree("DAREGRESS");
  1097. Owned<IPropertyTree> tree = createPTreeFromXMLString("<TestSub2><a><b1><c/></b1><b2/><b3><d><e/></d></b3><b4><f/></b4></a></TestSub2>");
  1098. daRegress->setPropTree("TestSub2", tree.getClear());
  1099. conn->commit();
  1100. StringBuffer result;
  1101. Owned<CSubscriberContainer> sub1 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a", true);
  1102. Owned<CSubscriberContainer> sub2 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b1", false);
  1103. Owned<CSubscriberContainer> sub3 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b2", false);
  1104. Owned<CSubscriberContainer> sub4 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b1/c", false);
  1105. Owned<CSubscriberContainer> sub5 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b3", true);
  1106. Owned<CSubscriberContainer> sub6 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b4", false);
  1107. Owned<CSubscriberContainer> sub7 = new CSubscriberContainer(result, "/DAREGRESS/TestSub2/a/b4/sub", false);
  1108. MilliSleep(1000);
  1109. StringArray expectedResults;
  1110. expectedResults.append("/DAREGRESS/TestSub2/a");
  1111. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b1,testv");
  1112. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b2,testv");
  1113. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b1/c,testv");
  1114. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b1,testv");
  1115. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b2,testv");
  1116. expectedResults.append("/DAREGRESS/TestSub2/a");
  1117. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b3");
  1118. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b3");
  1119. expectedResults.append("/DAREGRESS/TestSub2/a|/DAREGRESS/TestSub2/a/b4,b4value|/DAREGRESS/TestSub2/a/b4/sub,subvalue");
  1120. StringArray props;
  1121. props.appendList("S:TestSub2/a,S:TestSub2/a/b1,S:TestSub2/a/b2,S:TestSub2/a/b1/c,S:TestSub2/a/b1/d,S:TestSub2/a/b2/e,S:TestSub2/a/b2/e/f,D:TestSub2/a/b3/d/e,D:TestSub2/a/b3/d,R:TestSub2/a/b4", ",");
  1122. assertex(expectedResults.ordinality() == props.ordinality());
  1123. ForEachItemIn(p, props)
  1124. {
  1125. result.clear(); // filled by subscriber notifications
  1126. const char *cmd = props.item(p);
  1127. const char *propPath=cmd+2;
  1128. switch (*cmd)
  1129. {
  1130. case 'S':
  1131. {
  1132. PROGLOG("Changing %s", propPath);
  1133. daRegress->setProp(propPath, "testv");
  1134. break;
  1135. }
  1136. case 'D':
  1137. {
  1138. PROGLOG("Deleting %s", propPath);
  1139. daRegress->removeProp(propPath);
  1140. break;
  1141. }
  1142. case 'R':
  1143. {
  1144. PROGLOG("Replacing tree %s", propPath);
  1145. Owned<IPropertyTree> tree = createPTreeFromXMLString("<b4><sub><g/>subvalue</sub>b4value</b4>");
  1146. daRegress->setPropTree(propPath, tree.getClear());
  1147. break;
  1148. }
  1149. default:
  1150. throwUnexpected();
  1151. }
  1152. conn->commit();
  1153. MilliSleep(100); // time for notifications to come through
  1154. PROGLOG("Checking results");
  1155. StringArray resultArray;
  1156. resultArray.appendList(result, "|");
  1157. result.clear();
  1158. resultArray.sortAscii();
  1159. ForEachItemIn(r, resultArray)
  1160. {
  1161. if (result.length())
  1162. result.append("|");
  1163. result.append(resultArray.item(r));
  1164. }
  1165. const char *expectedResult = expectedResults.item(p);
  1166. if (0 == strcmp(expectedResult, result))
  1167. PROGLOG("testSDSSubs2 [ %s ]: MATCH", cmd);
  1168. else
  1169. {
  1170. VStringBuffer errMsg("testSDSSubs2 [ %s ]: MISMATCH", cmd);
  1171. errMsg.newline().append("Expected: ").append(expectedResult);
  1172. errMsg.newline().append("Got: ").append(result);
  1173. PROGLOG("%s", errMsg.str());
  1174. CPPUNIT_ASSERT_MESSAGE(errMsg.str(), 0);
  1175. }
  1176. }
  1177. }
  1178. void testSDSNodeSubs()
  1179. {
  1180. class CResults
  1181. {
  1182. StringArray results;
  1183. CRC32 crc;
  1184. CriticalSection crit;
  1185. public:
  1186. void add(const char *out)
  1187. {
  1188. PROGLOG("%s", out);
  1189. CriticalBlock b(crit); // notify() and therefore add() can be called on multiple threads
  1190. results.append(out);
  1191. }
  1192. unsigned getCRC()
  1193. {
  1194. results.sortAscii();
  1195. ForEachItemIn(r, results)
  1196. {
  1197. const char *result = results.item(r);
  1198. crc.tally(strlen(result), result);
  1199. }
  1200. PROGLOG("CRC = %x", crc.get());
  1201. results.kill();
  1202. return crc.get();
  1203. }
  1204. };
  1205. class CSubscriber : CSimpleInterface, implements ISDSNodeSubscription
  1206. {
  1207. StringAttr path;
  1208. CResults &results;
  1209. unsigned expectedNotifications;
  1210. std::atomic<unsigned> notifications = {0};
  1211. Semaphore joinSem;
  1212. public:
  1213. IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
  1214. CSubscriber(const char *_path, CResults &_results, unsigned _expectedNotifications)
  1215. : path(_path), results(_results), expectedNotifications(_expectedNotifications)
  1216. {
  1217. if (0 == expectedNotifications)
  1218. joinSem.signal();
  1219. }
  1220. virtual void notify(SubscriptionId id, SDSNotifyFlags flags, unsigned valueLen, const void *valueData)
  1221. {
  1222. StringAttr value;
  1223. if (valueLen)
  1224. value.set((const char *)valueData, valueLen);
  1225. VStringBuffer res("Subscriber(%s): flags=%d, value=%s", path.get(), flags, 0==valueLen ? "(none)" : value.get());
  1226. results.add(res);
  1227. if (++notifications == expectedNotifications)
  1228. joinSem.signal();
  1229. }
  1230. void join()
  1231. {
  1232. if (joinSem.wait(5000))
  1233. {
  1234. MilliSleep(100); // wait a bit, see if get more than expected
  1235. unsigned n = notifications;
  1236. if (n == expectedNotifications)
  1237. {
  1238. VStringBuffer out("Subscriber(%s): %d notifications received", path.get(), n);
  1239. results.add(out);
  1240. return;
  1241. }
  1242. }
  1243. VStringBuffer out("Expected %d notifications, received %d", expectedNotifications, notifications.load());
  1244. results.add(out);
  1245. }
  1246. };
  1247. // setup
  1248. Owned<IRemoteConnection> conn = querySDS().connect("/DAREGRESS/NodeSubTest", myProcessSession(), RTM_CREATE, 1000000);
  1249. IPropertyTree *root = conn->queryRoot();
  1250. unsigned i, ai;
  1251. for (i=0; i<10; i++)
  1252. {
  1253. VStringBuffer name("node%d", i+1);
  1254. IPropertyTree *sub = root->setPropTree(name, createPTree());
  1255. for (ai=0; ai<2; ai++)
  1256. {
  1257. VStringBuffer name("@attr%d", i+1);
  1258. VStringBuffer val("val%d", i+1);
  1259. sub->setProp(name, val);
  1260. }
  1261. }
  1262. conn.clear();
  1263. CResults results;
  1264. {
  1265. const char *testPath = "/DAREGRESS/NodeSubTest/doesnotexist";
  1266. Owned<CSubscriber> subscriber = new CSubscriber(testPath, results, 0);
  1267. try
  1268. {
  1269. querySDS().subscribeExact(testPath, *subscriber, true);
  1270. throwUnexpected();
  1271. }
  1272. catch(IException *e)
  1273. {
  1274. if (SDSExcpt_SubscriptionNoMatch != e->errorCode())
  1275. throw;
  1276. results.add("Correctly failed to add subscriber to non-existent node.");
  1277. }
  1278. subscriber.clear();
  1279. }
  1280. {
  1281. const char *testPath = "/DAREGRESS/NodeSubTest/node1";
  1282. Owned<CSubscriber> subscriber = new CSubscriber(testPath, results, 2*5+1+1);
  1283. SubscriptionId id = querySDS().subscribeExact(testPath, *subscriber, false);
  1284. sdsNodeCommit(testPath, 1, 1, false);
  1285. sdsNodeCommit(testPath, 1, 1, true); // will delete 'node1'
  1286. subscriber->join();
  1287. querySDS().unsubscribeExact(id); // will actually be a NOP, as will be already unsubscribed when 'node1' deleted.
  1288. }
  1289. {
  1290. const char *testPath = "/DAREGRESS/NodeSubTest/node*";
  1291. Owned<CSubscriber> subscriber = new CSubscriber(testPath, results, 9*6);
  1292. SubscriptionId id = querySDS().subscribeExact(testPath, *subscriber, false);
  1293. sdsNodeCommit(testPath, 2, 10, false);
  1294. subscriber->join();
  1295. querySDS().unsubscribeExact(id);
  1296. }
  1297. {
  1298. UInt64Array subscriberIds;
  1299. IArrayOf<CSubscriber> subscribers;
  1300. for (i=2; i<=10; i++) // NB: from 2, as 'node1' deleted in previous tests
  1301. {
  1302. for (ai=0; ai<2; ai++)
  1303. {
  1304. VStringBuffer path("/DAREGRESS/NodeSubTest/node%d[@attr%d=\"val%d\"]", i, i, i);
  1305. Owned<CSubscriber> subscriber = new CSubscriber(path, results, 11);
  1306. SubscriptionId id = querySDS().subscribeExact(path, *subscriber, 0==ai);
  1307. subscribers.append(* subscriber.getClear());
  1308. subscriberIds.append(id);
  1309. }
  1310. }
  1311. const char *testPath = "/DAREGRESS/NodeSubTest/node*";
  1312. Owned<CSubscriber> subscriber = new CSubscriber(testPath, results, 9*5+9*(5+1));
  1313. SubscriptionId id = querySDS().subscribeExact(testPath, *subscriber, false);
  1314. sdsNodeCommit(testPath, 2, 10, false);
  1315. sdsNodeCommit(testPath, 2, 10, true);
  1316. subscriber->join();
  1317. querySDS().unsubscribeExact(id);
  1318. ForEachItemIn(s, subscriberIds)
  1319. {
  1320. subscribers.item(s).join();
  1321. querySDS().unsubscribeExact(subscriberIds.item(s));
  1322. }
  1323. }
  1324. ASSERT(0xa68e2324 == results.getCRC() && "SDS Node notifcation differences");
  1325. }
  1326. };
  1327. CPPUNIT_TEST_SUITE_REGISTRATION( CDaliSDSTests );
  1328. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliSDSTests, "CDaliSDSTests" );
  1329. // ================================================================================== UNIT TESTS
  1330. static IFileDescriptor *createDescriptor(const char* dir, const char* name, unsigned parts, unsigned recSize, unsigned index=0)
  1331. {
  1332. Owned<IPropertyTree> pp = createPTree("Part");
  1333. Owned<IFileDescriptor>fdesc = createFileDescriptor();
  1334. fdesc->setDefaultDir(dir);
  1335. StringBuffer s;
  1336. SocketEndpoint ep;
  1337. ep.setLocalHost(0);
  1338. StringBuffer ip;
  1339. ep.getIpText(ip);
  1340. for (unsigned k=0;k<parts;k++) {
  1341. s.clear().append(ip);
  1342. Owned<INode> node = createINode(s.str());
  1343. pp->setPropInt64("@size",recSize);
  1344. s.clear().append(name);
  1345. if (index)
  1346. s.append(index);
  1347. s.append("._").append(k+1).append("_of_").append(parts);
  1348. fdesc->setPart(k,node,s.str(),pp);
  1349. }
  1350. fdesc->queryProperties().setPropInt("@recordSize",recSize);
  1351. fdesc->setDefaultDir(dir);
  1352. return fdesc.getClear();
  1353. }
  1354. static void setupDFS(const IContextLogger &logctx, const char *scope, unsigned supersToDel=3, unsigned subsToCreate=4)
  1355. {
  1356. StringBuffer bufScope;
  1357. bufScope.append("regress::").append(scope);
  1358. StringBuffer bufDir;
  1359. bufDir.append("regress/").append(scope);
  1360. logctx.CTXLOG("Cleaning up '%s' scope", bufScope.str());
  1361. for (unsigned i=1; i<=supersToDel; i++) {
  1362. StringBuffer super = bufScope;
  1363. super.append("::super").append(i);
  1364. if (dir.exists(super.str(),user,false,true))
  1365. ASSERT(dir.removeEntry(super.str(), user) && "Can't remove super-file");
  1366. }
  1367. logctx.CTXLOG("Creating 'regress::trans' subfiles(1,%d)", subsToCreate);
  1368. for (unsigned i=1; i<=subsToCreate; i++) {
  1369. StringBuffer name;
  1370. name.append("sub").append(i);
  1371. StringBuffer sub = bufScope;
  1372. sub.append("::").append(name);
  1373. // Remove first
  1374. if (dir.exists(sub.str(),user,true,false))
  1375. ASSERT(dir.removeEntry(sub.str(), user) && "Can't remove sub-file");
  1376. try {
  1377. // Create the sub file with an arbitrary format
  1378. Owned<IFileDescriptor> subd = createDescriptor(bufDir.str(), name.str(), 1, 17);
  1379. Owned<IPartDescriptor> partd = subd->getPart(0);
  1380. RemoteFilename rfn;
  1381. partd->getFilename(0, rfn);
  1382. StringBuffer fname;
  1383. rfn.getPath(fname);
  1384. recursiveCreateDirectoryForFile(fname.str());
  1385. OwnedIFile ifile = createIFile(fname.str());
  1386. Owned<IFileIO> io;
  1387. io.setown(ifile->open(IFOcreate));
  1388. io->write(0, 17, "12345678901234567");
  1389. io->close();
  1390. Owned<IDistributedFile> dsub = dir.createNew(subd);
  1391. dsub->attach(sub.str(),user);
  1392. } catch (IException *e) {
  1393. StringBuffer msg;
  1394. e->errorMessage(msg);
  1395. logctx.CTXLOG("Caught exception while creating file in DFS: %s", msg.str());
  1396. e->Release();
  1397. ASSERT(0 && "Exception Caught in setupDFS - is the directory writeable by this user?");
  1398. }
  1399. // Make sure it got created
  1400. ASSERT(dir.exists(sub.str(),user,true,false) && "Can't add physical files");
  1401. }
  1402. }
  1403. class CDaliDFSTests : public CppUnit::TestFixture
  1404. {
  1405. CPPUNIT_TEST_SUITE(CDaliDFSTests);
  1406. CPPUNIT_TEST(testInit);
  1407. CPPUNIT_TEST(testGroups);
  1408. CPPUNIT_TEST(testMultiCluster);
  1409. CPPUNIT_TEST(testDFSTrans);
  1410. CPPUNIT_TEST(testDFSPromote);
  1411. CPPUNIT_TEST(testDFSDel);
  1412. CPPUNIT_TEST(testDFSRename);
  1413. CPPUNIT_TEST(testDFSClearAdd);
  1414. CPPUNIT_TEST(testDFSRename2);
  1415. CPPUNIT_TEST(testDFSRenameThenDelete);
  1416. CPPUNIT_TEST(testDFSRemoveSuperSub);
  1417. // This test requires access to an external IP with dafilesrv running
  1418. // CPPUNIT_TEST(testDFSRename3);
  1419. CPPUNIT_TEST_SUITE_END();
  1420. void testGrp(SocketEndpointArray &epa)
  1421. {
  1422. Owned<IGroup> grp = createIGroup(epa);
  1423. StringBuffer s;
  1424. grp->getText(s);
  1425. printf("'%s'\n",s.str());
  1426. Owned<IGroup> grp2 = createIGroup(s.str());
  1427. if (grp->compare(grp2)!=GRidentical)
  1428. {
  1429. s.clear().append("Group did not match: ");
  1430. grp->getText(s);
  1431. CPPUNIT_ASSERT_MESSAGE(s.str(), 0);
  1432. }
  1433. }
  1434. const IContextLogger &logctx;
  1435. public:
  1436. CDaliDFSTests() : logctx(queryDummyContextLogger())
  1437. {
  1438. }
  1439. ~CDaliDFSTests()
  1440. {
  1441. daliClientEnd();
  1442. }
  1443. void testInit()
  1444. {
  1445. daliClientInit();
  1446. }
  1447. void testDFSTrans()
  1448. {
  1449. setupDFS(logctx, "trans");
  1450. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user);
  1451. // Auto-commit
  1452. logctx.CTXLOG("Auto-commit test (inactive transaction)");
  1453. Owned<IDistributedSuperFile> sfile1 = dir.createSuperFile("regress::trans::super1",user , false, false, transaction);
  1454. sfile1->addSubFile("regress::trans::sub1", false, NULL, false, transaction);
  1455. sfile1->addSubFile("regress::trans::sub2", false, NULL, false, transaction);
  1456. sfile1.clear();
  1457. sfile1.setown(dir.lookupSuperFile("regress::trans::super1", user, transaction));
  1458. ASSERT(sfile1.get() && "non-transactional add super1 failed");
  1459. ASSERT(sfile1->numSubFiles() == 2 && "auto-commit add sub failed, not all subs were added");
  1460. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub1") == 0 && "auto-commit add sub failed, wrong name for sub1");
  1461. ASSERT(strcmp(sfile1->querySubFile(1).queryLogicalName(), "regress::trans::sub2") == 0 && "auto-commit add sub failed, wrong name for sub2");
  1462. sfile1.clear();
  1463. // Rollback
  1464. logctx.CTXLOG("Rollback test (active transaction)");
  1465. transaction->start();
  1466. Owned<IDistributedSuperFile> sfile2 = dir.createSuperFile("regress::trans::super2", user, false, false, transaction);
  1467. sfile2->addSubFile("regress::trans::sub3", false, NULL, false, transaction);
  1468. sfile2->addSubFile("regress::trans::sub4", false, NULL, false, transaction);
  1469. transaction->rollback();
  1470. ASSERT(sfile2->numSubFiles() == 0 && "transactional rollback failed, some subs were added");
  1471. sfile2.clear();
  1472. sfile2.setown(dir.lookupSuperFile("regress::trans::super2", user, transaction));
  1473. ASSERT(!sfile2.get() && "transactional rollback super2 failed, it exists!");
  1474. // Commit
  1475. logctx.CTXLOG("Commit test (active transaction)");
  1476. transaction->start();
  1477. Owned<IDistributedSuperFile> sfile3 = dir.createSuperFile("regress::trans::super3", user, false, false, transaction);
  1478. sfile3->addSubFile("regress::trans::sub3", false, NULL, false, transaction);
  1479. sfile3->addSubFile("regress::trans::sub4", false, NULL, false, transaction);
  1480. transaction->commit();
  1481. sfile3.clear();
  1482. sfile3.setown(dir.lookupSuperFile("regress::trans::super3", user, transaction));
  1483. ASSERT(sfile3.get() && "transactional add super3 failed");
  1484. ASSERT(sfile3->numSubFiles() == 2 && "transactional add sub failed, not all subs were added");
  1485. ASSERT(strcmp(sfile3->querySubFile(0).queryLogicalName(), "regress::trans::sub3") == 0 && "transactional add sub failed, wrong name for sub3");
  1486. ASSERT(strcmp(sfile3->querySubFile(1).queryLogicalName(), "regress::trans::sub4") == 0 && "transactional add sub failed, wrong name for sub4");
  1487. sfile3.clear();
  1488. }
  1489. void testDFSPromote()
  1490. {
  1491. setupDFS(logctx, "trans");
  1492. unsigned timeout = 1000; // 1s
  1493. /* Make the meta info of one of the subfiles mismatch the rest, as subfiles are promoted through
  1494. * the super files, this should _not_ cause an issue, as no single super file will contain
  1495. * mismatched subfiles.
  1496. */
  1497. Owned<IDistributedFile> sub1 = dir.lookup("regress::trans::sub1", user, false, false, false, NULL, timeout);
  1498. assertex(sub1);
  1499. sub1->lockProperties();
  1500. sub1->queryAttributes().setPropBool("@local", true);
  1501. sub1->unlockProperties();
  1502. sub1.clear();
  1503. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user);
  1504. // ===============================================================================
  1505. // Don't change these parameters, or you'll have to change all ERROR tests below
  1506. const char *sfnames[3] = {
  1507. "regress::trans::super1", "regress::trans::super2", "regress::trans::super3"
  1508. };
  1509. bool delsub = false;
  1510. bool createonlyone = true;
  1511. // ===============================================================================
  1512. StringArray outlinked;
  1513. logctx.CTXLOG("Promote (1, -, -) - first iteration");
  1514. dir.promoteSuperFiles(3, sfnames, "regress::trans::sub1", delsub, createonlyone, user, timeout, outlinked);
  1515. {
  1516. Owned<IDistributedSuperFile> sfile1 = dir.lookupSuperFile("regress::trans::super1", user, NULL, timeout);
  1517. ASSERT(sfile1.get() && "promote failed, super1 doesn't exist");
  1518. ASSERT(sfile1->numSubFiles() == 1 && "promote failed, super1 should have one subfile");
  1519. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub1") == 0 && "promote failed, wrong name for sub1");
  1520. Owned<IDistributedSuperFile> sfile2 = dir.lookupSuperFile("regress::trans::super2", user, NULL, timeout);
  1521. ASSERT(!sfile2.get() && "promote failed, super2 does exist");
  1522. ASSERT(outlinked.length() == 0 && "promote failed, outlinked expected empty");
  1523. }
  1524. logctx.CTXLOG("Promote (2, 1, -) - second iteration");
  1525. dir.promoteSuperFiles(3, sfnames, "regress::trans::sub2", delsub, createonlyone, user, timeout, outlinked);
  1526. {
  1527. Owned<IDistributedSuperFile> sfile1 = dir.lookupSuperFile("regress::trans::super1", user, NULL, timeout);
  1528. ASSERT(sfile1.get() && "promote failed, super1 doesn't exist");
  1529. ASSERT(sfile1->numSubFiles() == 1 && "promote failed, super1 should have one subfile");
  1530. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub2") == 0 && "promote failed, wrong name for sub2");
  1531. Owned<IDistributedSuperFile> sfile2 = dir.lookupSuperFile("regress::trans::super2", user, NULL, timeout);
  1532. ASSERT(sfile2.get() && "promote failed, super2 doesn't exist");
  1533. ASSERT(sfile2->numSubFiles() == 1 && "promote failed, super2 should have one subfile");
  1534. ASSERT(strcmp(sfile2->querySubFile(0).queryLogicalName(), "regress::trans::sub1") == 0 && "promote failed, wrong name for sub1");
  1535. Owned<IDistributedSuperFile> sfile3 = dir.lookupSuperFile("regress::trans::super3", user, NULL, timeout);
  1536. ASSERT(!sfile3.get() && "promote failed, super3 does exist");
  1537. ASSERT(outlinked.length() == 0 && "promote failed, outlinked expected empty");
  1538. }
  1539. logctx.CTXLOG("Promote (3, 2, 1) - third iteration");
  1540. dir.promoteSuperFiles(3, sfnames, "regress::trans::sub3", delsub, createonlyone, user, timeout, outlinked);
  1541. {
  1542. Owned<IDistributedSuperFile> sfile1 = dir.lookupSuperFile("regress::trans::super1", user, NULL, timeout);
  1543. ASSERT(sfile1.get() &&* "promote failed, super1 doesn't exist");
  1544. ASSERT(sfile1->numSubFiles() == 1 && "promote failed, super1 should have one subfile");
  1545. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub3") == 0 && "promote failed, wrong name for sub3");
  1546. Owned<IDistributedSuperFile> sfile2 = dir.lookupSuperFile("regress::trans::super2", user, NULL, timeout);
  1547. ASSERT(sfile2.get() && "promote failed, super2 doesn't exist");
  1548. ASSERT(sfile2->numSubFiles() == 1 && "promote failed, super2 should have one subfile");
  1549. ASSERT(strcmp(sfile2->querySubFile(0).queryLogicalName(), "regress::trans::sub2") == 0 && "promote failed, wrong name for sub2");
  1550. Owned<IDistributedSuperFile> sfile3 = dir.lookupSuperFile("regress::trans::super3", user, NULL, timeout);
  1551. ASSERT(sfile3.get() && "promote failed, super3 doesn't exist");
  1552. ASSERT(sfile3->numSubFiles() == 1 && "promote failed, super3 should have one subfile");
  1553. ASSERT(strcmp(sfile3->querySubFile(0).queryLogicalName(), "regress::trans::sub1") == 0 && "promote failed, wrong name for sub1");
  1554. ASSERT(outlinked.length() == 0 && "promote failed, outlinked expected empty");
  1555. }
  1556. logctx.CTXLOG("Promote (4, 3, 2) - fourth iteration, expect outlinked");
  1557. dir.promoteSuperFiles(3, sfnames, "regress::trans::sub4", delsub, createonlyone, user, timeout, outlinked);
  1558. {
  1559. Owned<IDistributedSuperFile> sfile1 = dir.lookupSuperFile("regress::trans::super1", user, NULL, timeout);
  1560. ASSERT(sfile1.get() && "promote failed, super1 doesn't exist");
  1561. ASSERT(sfile1->numSubFiles() == 1 && "promote failed, super1 should have one subfile");
  1562. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub4") == 0 && "promote failed, wrong name for sub4");
  1563. Owned<IDistributedSuperFile> sfile2 = dir.lookupSuperFile("regress::trans::super2", user, NULL, timeout);
  1564. ASSERT(sfile2.get() && "promote failed, super2 doesn't exist");
  1565. ASSERT(sfile2->numSubFiles() == 1 && "promote failed, super2 should have one subfile");
  1566. ASSERT(strcmp(sfile2->querySubFile(0).queryLogicalName(), "regress::trans::sub3") == 0 && "promote failed, wrong name for sub3");
  1567. Owned<IDistributedSuperFile> sfile3 = dir.lookupSuperFile("regress::trans::super3", user, NULL, timeout);
  1568. ASSERT(sfile3.get() && "promote failed, super3 doesn't exist");
  1569. ASSERT(sfile3->numSubFiles() == 1 && "promote failed, super3 should have one subfile");
  1570. ASSERT(strcmp(sfile3->querySubFile(0).queryLogicalName(), "regress::trans::sub2") == 0 && "promote failed, wrong name for sub2");
  1571. ASSERT(outlinked.length() == 1 && "promote failed, outlinked expected only one item");
  1572. ASSERT(strcmp(outlinked.popGet(), "regress::trans::sub1") == 0 && "promote failed, outlinked expected to be sub1");
  1573. Owned<IDistributedFile> sub1 = dir.lookup("regress::trans::sub1", user, false, false, false, NULL, timeout);
  1574. ASSERT(sub1.get() && "promote failed, sub1 was physically deleted");
  1575. }
  1576. logctx.CTXLOG("Promote ([2,3], 4, 3) - fifth iteration, two in-files");
  1577. dir.promoteSuperFiles(3, sfnames, "regress::trans::sub2,regress::trans::sub3", delsub, createonlyone, user, timeout, outlinked);
  1578. {
  1579. Owned<IDistributedSuperFile> sfile1 = dir.lookupSuperFile("regress::trans::super1", user, NULL, timeout);
  1580. ASSERT(sfile1.get() && "promote failed, super1 doesn't exist");
  1581. ASSERT(sfile1->numSubFiles() == 2 && "promote failed, super1 should have two subfiles");
  1582. ASSERT(strcmp(sfile1->querySubFile(0).queryLogicalName(), "regress::trans::sub2") == 0 && "promote failed, wrong name for sub1");
  1583. ASSERT(strcmp(sfile1->querySubFile(1).queryLogicalName(), "regress::trans::sub3") == 0 && "promote failed, wrong name for sub2");
  1584. Owned<IDistributedSuperFile> sfile2 = dir.lookupSuperFile("regress::trans::super2", user, NULL, timeout);
  1585. ASSERT(sfile2.get() && "promote failed, super2 doesn't exist");
  1586. ASSERT(sfile2->numSubFiles() == 1 && "promote failed, super2 should have one subfile");
  1587. ASSERT(strcmp(sfile2->querySubFile(0).queryLogicalName(), "regress::trans::sub4") == 0 && "promote failed, wrong name for sub4");
  1588. Owned<IDistributedSuperFile> sfile3 = dir.lookupSuperFile("regress::trans::super3", user, NULL, timeout);
  1589. ASSERT(sfile3.get() && "promote failed, super3 doesn't exist");
  1590. ASSERT(sfile3->numSubFiles() == 1 && "promote failed, super3 should have one subfile");
  1591. ASSERT(strcmp(sfile3->querySubFile(0).queryLogicalName(), "regress::trans::sub3") == 0 && "promote failed, wrong name for sub3");
  1592. ASSERT(outlinked.length() == 1 && "promote failed, outlinked expected only one item");
  1593. ASSERT(strcmp(outlinked.popGet(), "regress::trans::sub2") == 0 && "promote failed, outlinked expected to be sub2");
  1594. Owned<IDistributedFile> sub1 = dir.lookup("regress::trans::sub1", user, false, false, false, NULL, timeout);
  1595. ASSERT(sub1.get() && "promote failed, sub1 was physically deleted");
  1596. Owned<IDistributedFile> sub2 = dir.lookup("regress::trans::sub2", user, false, false, false, NULL, timeout);
  1597. ASSERT(sub2.get() && "promote failed, sub2 was physically deleted");
  1598. }
  1599. }
  1600. void testMultiCluster()
  1601. {
  1602. Owned<IGroup> grp1 = createIGroup("192.168.51.1-5");
  1603. Owned<IGroup> grp2 = createIGroup("192.168.16.1-5");
  1604. Owned<IGroup> grp3 = createIGroup("192.168.53.1-5");
  1605. queryNamedGroupStore().add("testgrp1",grp1);
  1606. queryNamedGroupStore().add("testgrp2",grp2);
  1607. queryNamedGroupStore().add("testgrp3",grp3);
  1608. Owned<IFileDescriptor> fdesc = createFileDescriptor();
  1609. fdesc->setDefaultDir("/c$/thordata/test");
  1610. fdesc->setPartMask("testfile1._$P$_of_$N$");
  1611. fdesc->setNumParts(5);
  1612. ClusterPartDiskMapSpec mapping;
  1613. fdesc->addCluster(grp1,mapping);
  1614. fdesc->addCluster(grp2,mapping);
  1615. fdesc->addCluster(grp3,mapping);
  1616. removeLogical("test::testfile1", user);
  1617. Owned<IDistributedFile> file = queryDistributedFileDirectory().createNew(fdesc);
  1618. removeLogical("test::testfile1", user);
  1619. file->attach("test::testfile1",user);
  1620. StringBuffer name;
  1621. unsigned i;
  1622. for (i=0;i<file->numClusters();i++)
  1623. PROGLOG("cluster[%d] = %s",i,file->getClusterName(i,name.clear()).str());
  1624. file.clear();
  1625. file.setown(queryDistributedFileDirectory().lookup("test::testfile1",user));
  1626. for (i=0;i<file->numClusters();i++)
  1627. PROGLOG("cluster[%d] = %s",i,file->getClusterName(i,name.clear()).str());
  1628. file.clear();
  1629. file.setown(queryDistributedFileDirectory().lookup("test::testfile1@testgrp1",user));
  1630. for (i=0;i<file->numClusters();i++)
  1631. PROGLOG("cluster[%d] = %s",i,file->getClusterName(i,name.clear()).str());
  1632. file.clear();
  1633. removeLogical("test::testfile1@testgrp2", user);
  1634. file.setown(queryDistributedFileDirectory().lookup("test::testfile1",user));
  1635. for (i=0;i<file->numClusters();i++)
  1636. PROGLOG("cluster[%d] = %s",i,file->getClusterName(i,name.clear()).str());
  1637. }
  1638. void testGroups()
  1639. {
  1640. SocketEndpointArray epa;
  1641. SocketEndpoint ep;
  1642. Owned<IGroup> grp;
  1643. ep.set("10.150.10.80");
  1644. epa.append(ep);
  1645. testGrp(epa);
  1646. ep.set("10.150.10.81");
  1647. epa.append(ep);
  1648. testGrp(epa);
  1649. ep.set("10.150.10.82");
  1650. epa.append(ep);
  1651. testGrp(epa);
  1652. ep.set("10.150.10.83:111");
  1653. epa.append(ep);
  1654. testGrp(epa);
  1655. ep.set("10.150.10.84:111");
  1656. epa.append(ep);
  1657. testGrp(epa);
  1658. ep.set("10.150.10.84:111");
  1659. epa.append(ep);
  1660. testGrp(epa);
  1661. ep.set("10.150.10.84:111");
  1662. epa.append(ep);
  1663. testGrp(epa);
  1664. ep.set("10.150.10.84:111");
  1665. epa.append(ep);
  1666. testGrp(epa);
  1667. ep.set("10.150.10.85:111");
  1668. epa.append(ep);
  1669. testGrp(epa);
  1670. ep.set("10.150.10.86:111");
  1671. epa.append(ep);
  1672. testGrp(epa);
  1673. ep.set("10.150.10.87");
  1674. epa.append(ep);
  1675. testGrp(epa);
  1676. ep.set("10.150.10.87");
  1677. epa.append(ep);
  1678. testGrp(epa);
  1679. ep.set("10.150.10.88");
  1680. epa.append(ep);
  1681. testGrp(epa);
  1682. ep.set("10.150.11.88");
  1683. epa.append(ep);
  1684. testGrp(epa);
  1685. ep.set("10.173.10.88");
  1686. epa.append(ep);
  1687. testGrp(epa);
  1688. ep.set("10.173.10.88:22222");
  1689. epa.append(ep);
  1690. testGrp(epa);
  1691. ep.set("192.168.10.88");
  1692. epa.append(ep);
  1693. testGrp(epa);
  1694. }
  1695. void testDFSDel()
  1696. {
  1697. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1698. setupDFS(logctx, "del");
  1699. // Sub-file deletion
  1700. logctx.CTXLOG("Creating regress::del::super1 and attaching sub");
  1701. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::del::super1", user, false, false, transaction);
  1702. sfile->addSubFile("regress::del::sub1", false, NULL, false, transaction);
  1703. sfile->addSubFile("regress::del::sub4", false, NULL, false, transaction);
  1704. sfile.clear();
  1705. logctx.CTXLOG("Deleting regress::del::sub1, should fail");
  1706. try {
  1707. if (dir.removeEntry("regress::del::sub1", user, transaction)) {
  1708. ASSERT(0 && "Could remove sub, this will make the DFS inconsistent!");
  1709. return;
  1710. }
  1711. } catch (IException *e) {
  1712. // expecting an exception
  1713. e->Release();
  1714. }
  1715. logctx.CTXLOG("Removing regress::del::sub1 from super1, no del");
  1716. sfile.setown(transaction->lookupSuperFile("regress::del::super1"));
  1717. sfile->removeSubFile("regress::del::sub1", false, false, transaction);
  1718. ASSERT(sfile->numSubFiles() == 1 && "File sub1 was not removed from super1");
  1719. sfile.clear();
  1720. ASSERT(dir.exists("regress::del::sub1", user) && "File sub1 was removed from the file system");
  1721. logctx.CTXLOG("Removing regress::del::sub4 from super1, del");
  1722. sfile.setown(transaction->lookupSuperFile("regress::del::super1"));
  1723. sfile->removeSubFile("regress::del::sub4", true, false, transaction);
  1724. ASSERT(!sfile->numSubFiles() && "File sub4 was not removed from super1");
  1725. sfile.clear();
  1726. ASSERT(!dir.exists("regress::del::sub4", user) && "File sub4 was NOT removed from the file system");
  1727. // Logical Remove
  1728. logctx.CTXLOG("Deleting 'regress::del::super1, should work");
  1729. ASSERT(dir.removeEntry("regress::del::super1", user) && "Can't remove super1");
  1730. logctx.CTXLOG("Deleting 'regress::del::sub1 autoCommit, should work");
  1731. ASSERT(dir.removeEntry("regress::del::sub1", user) && "Can't remove sub1");
  1732. logctx.CTXLOG("Removing 'regress::del::sub2 - rollback");
  1733. transaction->start();
  1734. dir.removeEntry("regress::del::sub2", user, transaction);
  1735. transaction->rollback();
  1736. ASSERT(dir.exists("regress::del::sub2", user, true, false) && "Shouldn't have removed sub2 on rollback");
  1737. logctx.CTXLOG("Removing 'regress::del::sub2 - commit");
  1738. transaction->start();
  1739. dir.removeEntry("regress::del::sub2", user, transaction);
  1740. transaction->commit();
  1741. ASSERT(!dir.exists("regress::del::sub2", user, true, false) && "Should have removed sub2 on commit");
  1742. // Physical Remove
  1743. logctx.CTXLOG("Physically removing 'regress::del::sub3 - rollback");
  1744. transaction->start();
  1745. dir.removeEntry("regress::del::sub3", user, transaction);
  1746. transaction->rollback();
  1747. ASSERT(dir.exists("regress::del::sub3", user, true, false) && "Shouldn't have removed sub3 on rollback");
  1748. logctx.CTXLOG("Physically removing 'regress::del::sub3 - commit");
  1749. transaction->start();
  1750. dir.removeEntry("regress::del::sub3", user, transaction);
  1751. transaction->commit();
  1752. ASSERT(!dir.exists("regress::del::sub3", user, true, false) && "Should have removed sub3 on commit");
  1753. }
  1754. void testDFSRename()
  1755. {
  1756. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1757. if (dir.exists("regress::rename::other1",user,false,false))
  1758. ASSERT(dir.removeEntry("regress::rename::other1", user) && "Can't remove 'regress::rename::other1'");
  1759. if (dir.exists("regress::rename::other2",user,false,false))
  1760. ASSERT(dir.removeEntry("regress::rename::other2", user) && "Can't remove 'regress::rename::other2'");
  1761. setupDFS(logctx, "rename");
  1762. try {
  1763. logctx.CTXLOG("Renaming 'regress::rename::sub1 to 'sub2' with auto-commit, should fail");
  1764. dir.renamePhysical("regress::rename::sub1", "regress::rename::sub2", user, transaction);
  1765. ASSERT(0 && "Renamed to existing file should have failed!");
  1766. return;
  1767. } catch (IException *e) {
  1768. // Expecting exception
  1769. e->Release();
  1770. }
  1771. logctx.CTXLOG("Renaming 'regress::rename::sub1 to 'other1' with auto-commit");
  1772. dir.renamePhysical("regress::rename::sub1", "regress::rename::other1", user, transaction);
  1773. ASSERT(dir.exists("regress::rename::other1", user, true, false) && "Renamed to other failed");
  1774. logctx.CTXLOG("Renaming 'regress::rename::sub2 to 'other2' and rollback");
  1775. transaction->start();
  1776. dir.renamePhysical("regress::rename::sub2", "regress::rename::other2", user, transaction);
  1777. transaction->rollback();
  1778. ASSERT(!dir.exists("regress::rename::other2", user, true, false) && "Renamed to other2 when it shouldn't");
  1779. logctx.CTXLOG("Renaming 'regress::rename::sub2 to 'other2' and commit");
  1780. transaction->start();
  1781. dir.renamePhysical("regress::rename::sub2", "regress::rename::other2", user, transaction);
  1782. transaction->commit();
  1783. ASSERT(dir.exists("regress::rename::other2", user, true, false) && "Renamed to other failed");
  1784. try {
  1785. logctx.CTXLOG("Renaming 'regress::rename::sub3 to 'sub3' with auto-commit, should fail");
  1786. dir.renamePhysical("regress::rename::sub3", "regress::rename::sub3", user, transaction);
  1787. ASSERT(0 && "Renamed to same file should have failed!");
  1788. return;
  1789. } catch (IException *e) {
  1790. // Expecting exception
  1791. e->Release();
  1792. }
  1793. // To make sure renamed files are cleaned properly
  1794. printf("Renaming 'regress::rename::other2 to 'sub2' on auto-commit\n");
  1795. dir.renamePhysical("regress::rename::other2", "regress::rename::sub2", user, transaction);
  1796. ASSERT(dir.exists("regress::rename::sub2", user, true, false) && "Renamed from other2 failed");
  1797. }
  1798. void testDFSClearAdd()
  1799. {
  1800. setupDFS(logctx, "clearadd");
  1801. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1802. logctx.CTXLOG("Creating regress::clearadd::super1 and attaching sub1 & sub4");
  1803. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::clearadd::super1", user, false, false, transaction);
  1804. sfile->addSubFile("regress::clearadd::sub1", false, NULL, false, transaction);
  1805. sfile->addSubFile("regress::clearadd::sub4", false, NULL, false, transaction);
  1806. sfile.clear();
  1807. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  1808. transaction->start();
  1809. logctx.CTXLOG("Removing sub1 from super1, within transaction");
  1810. sfile.setown(transaction->lookupSuperFile("regress::clearadd::super1"));
  1811. sfile->removeSubFile("regress::clearadd::sub1", false, false, transaction);
  1812. sfile.clear();
  1813. logctx.CTXLOG("Adding sub1 back into to super1, within transaction");
  1814. sfile.setown(transaction->lookupSuperFile("regress::clearadd::super1"));
  1815. sfile->addSubFile("regress::clearadd::sub1", false, NULL, false, transaction);
  1816. sfile.clear();
  1817. try
  1818. {
  1819. transaction->commit();
  1820. }
  1821. catch (IException *e)
  1822. {
  1823. StringBuffer eStr;
  1824. e->errorMessage(eStr);
  1825. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  1826. e->Release();
  1827. }
  1828. sfile.setown(dir.lookupSuperFile("regress::clearadd::super1", user));
  1829. ASSERT(NULL != sfile->querySubFileNamed("regress::clearadd::sub1") && "regress::clearadd::sub1, should be a subfile of super1");
  1830. // same but remove all (clear)
  1831. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  1832. transaction->start();
  1833. logctx.CTXLOG("Adding sub2 into to super1, within transaction");
  1834. sfile.setown(transaction->lookupSuperFile("regress::clearadd::super1"));
  1835. sfile->addSubFile("regress::clearadd::sub2", false, NULL, false, transaction);
  1836. sfile.clear();
  1837. logctx.CTXLOG("Removing all sub files from super1, within transaction");
  1838. sfile.setown(transaction->lookupSuperFile("regress::clearadd::super1"));
  1839. sfile->removeSubFile(NULL, false, false, transaction);
  1840. sfile.clear();
  1841. logctx.CTXLOG("Adding sub2 back into to super1, within transaction");
  1842. sfile.setown(transaction->lookupSuperFile("regress::clearadd::super1"));
  1843. sfile->addSubFile("regress::clearadd::sub2", false, NULL, false, transaction);
  1844. sfile.clear();
  1845. try
  1846. {
  1847. transaction->commit();
  1848. }
  1849. catch (IException *e)
  1850. {
  1851. StringBuffer eStr;
  1852. e->errorMessage(eStr);
  1853. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  1854. e->Release();
  1855. }
  1856. sfile.setown(dir.lookupSuperFile("regress::clearadd::super1", user));
  1857. ASSERT(NULL != sfile->querySubFileNamed("regress::clearadd::sub2") && "regress::clearadd::sub2, should be a subfile of super1");
  1858. ASSERT(NULL == sfile->querySubFileNamed("regress::clearadd::sub1") && "regress::clearadd::sub1, should NOT be a subfile of super1");
  1859. ASSERT(NULL == sfile->querySubFileNamed("regress::clearadd::sub4") && "regress::clearadd::sub4, should NOT be a subfile of super1");
  1860. ASSERT(1 == sfile->numSubFiles() && "regress::clearadd::super1 should contain 1 subfile");
  1861. }
  1862. void testDFSRename2()
  1863. {
  1864. setupDFS(logctx, "rename2");
  1865. /* Create a super and sub1 and sub4 in a auto-commit transaction
  1866. * Inside a transaction, do:
  1867. * a) rename sub2 to renamedsub2
  1868. * b) remove sub1
  1869. * c) add sub1
  1870. * d) add renamedsub2
  1871. * e) commit transaction
  1872. * f) renamed files existing and superfile contents
  1873. */
  1874. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1875. logctx.CTXLOG("Creating regress::rename2::super1 and attaching sub1 & sub4");
  1876. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::rename2::super1", user, false, false, transaction);
  1877. sfile->addSubFile("regress::rename2::sub1", false, NULL, false, transaction);
  1878. sfile->addSubFile("regress::rename2::sub4", false, NULL, false, transaction);
  1879. sfile.clear();
  1880. if (dir.exists("regress::rename2::renamedsub2",user,false,false))
  1881. ASSERT(dir.removeEntry("regress::rename2::renamedsub2", user) && "Can't remove 'regress::rename2::renamedsub2'");
  1882. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  1883. logctx.CTXLOG("Starting transaction");
  1884. transaction->start();
  1885. logctx.CTXLOG("Renaming regress::rename2::sub2 TO regress::rename2::renamedsub2");
  1886. dir.renamePhysical("regress::rename2::sub2", "regress::rename2::renamedsub2", user, transaction);
  1887. logctx.CTXLOG("Removing regress::rename2::sub1 from regress::rename2::super1");
  1888. sfile.setown(transaction->lookupSuperFile("regress::rename2::super1"));
  1889. sfile->removeSubFile("regress::rename2::sub1", false, false, transaction);
  1890. sfile.clear();
  1891. logctx.CTXLOG("Adding renamedsub2 to super1");
  1892. sfile.setown(transaction->lookupSuperFile("regress::rename2::super1"));
  1893. sfile->addSubFile("regress::rename2::renamedsub2", false, NULL, false, transaction);
  1894. sfile.clear();
  1895. logctx.CTXLOG("Adding back sub1 to super1");
  1896. sfile.setown(transaction->lookupSuperFile("regress::rename2::super1"));
  1897. sfile->addSubFile("regress::rename2::sub1", false, NULL, false, transaction);
  1898. sfile.clear();
  1899. try
  1900. {
  1901. logctx.CTXLOG("Committing transaction");
  1902. transaction->commit();
  1903. }
  1904. catch (IException *e)
  1905. {
  1906. StringBuffer eStr;
  1907. e->errorMessage(eStr);
  1908. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  1909. e->Release();
  1910. }
  1911. transaction.clear();
  1912. // validate..
  1913. ASSERT(dir.exists("regress::rename2::renamedsub2", user, true, false) && "regress::rename2::renamedsub2 should exist now transaction committed");
  1914. sfile.setown(dir.lookupSuperFile("regress::rename2::super1", user));
  1915. ASSERT(NULL != sfile->querySubFileNamed("regress::rename2::renamedsub2") && "regress::rename2::renamedsub2, should be a subfile of super1");
  1916. ASSERT(NULL != sfile->querySubFileNamed("regress::rename2::sub1") && "regress::rename2::sub1, should be a subfile of super1");
  1917. ASSERT(NULL == sfile->querySubFileNamed("regress::rename2::sub2") && "regress::rename2::sub2, should NOT be a subfile of super1");
  1918. ASSERT(NULL != sfile->querySubFileNamed("regress::rename2::sub4") && "regress::rename2::sub4, should be a subfile of super1");
  1919. ASSERT(3 == sfile->numSubFiles() && "regress::rename2::super1 should contain 4 subfiles");
  1920. }
  1921. void testDFSRenameThenDelete()
  1922. {
  1923. setupDFS(logctx, "renamedelete");
  1924. if (dir.exists("regress::renamedelete::renamedsub2",user,false,false))
  1925. ASSERT(dir.removeEntry("regress::renamedelete::renamedsub2", user) && "Can't remove 'regress::renamedelete::renamedsub2'");
  1926. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1927. logctx.CTXLOG("Starting transaction");
  1928. transaction->start();
  1929. logctx.CTXLOG("Renaming regress::renamedelete::sub2 TO regress::renamedelete::renamedsub2");
  1930. dir.renamePhysical("regress::renamedelete::sub2", "regress::renamedelete::renamedsub2", user, transaction);
  1931. logctx.CTXLOG("Removing regress::renamedelete::renamedsub2");
  1932. ASSERT(dir.removeEntry("regress::renamedelete::renamedsub2", user, transaction) && "Can't remove 'regress::rename2::renamedsub2'");
  1933. try
  1934. {
  1935. logctx.CTXLOG("Committing transaction");
  1936. transaction->commit();
  1937. }
  1938. catch (IException *e)
  1939. {
  1940. StringBuffer eStr;
  1941. e->errorMessage(eStr);
  1942. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  1943. e->Release();
  1944. }
  1945. transaction.clear();
  1946. // validate..
  1947. ASSERT(!dir.exists("regress::renamedelete::sub2", user, true, false) && "regress::renamedelete::sub2 should NOT exist now transaction has been committed");
  1948. ASSERT(!dir.exists("regress::renamedelete::renamedsub2", user, true, false) && "regress::renamedelete::renamedsub2 should NOT exist now transaction has been committed");
  1949. }
  1950. // NB: This test requires access (via dafilesrv) to an external IP (10.239.222.21 used below, but could be any)
  1951. void testDFSRename3()
  1952. {
  1953. setupDFS(logctx, "rename3");
  1954. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  1955. if (dir.exists("regress::tenwayfile",user))
  1956. ASSERT(dir.removeEntry("regress::tenwayfile", user) && "Can't remove");
  1957. Owned<IFileDescriptor> fdesc = createDescriptor("regress", "tenwayfile", 1, 17);
  1958. Owned<IGroup> grp1 = createIGroup("10.239.222.1");
  1959. ClusterPartDiskMapSpec mapping;
  1960. fdesc->setClusterGroup(0, grp1);
  1961. Linked<IPartDescriptor> part = fdesc->getPart(0);
  1962. RemoteFilename rfn;
  1963. part->getFilename(0, rfn);
  1964. StringBuffer path;
  1965. rfn.getPath(path);
  1966. recursiveCreateDirectoryForFile(path.str());
  1967. OwnedIFile ifile = createIFile(path.str());
  1968. Owned<IFileIO> io;
  1969. io.setown(ifile->open(IFOcreate));
  1970. io->write(0, 17, "12345678901234567");
  1971. io->close();
  1972. Owned<IDistributedFile> dsub = dir.createNew(fdesc);
  1973. dsub->attach("regress::tenwayfile", user);
  1974. dsub.clear();
  1975. fdesc.clear();
  1976. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  1977. transaction->start();
  1978. logctx.CTXLOG("Renaming regress::rename3::sub2 TO regress::tenwayfile@mythor");
  1979. dir.renamePhysical("regress::rename3::sub2", "regress::tenwayfile@mythor", user, transaction);
  1980. try
  1981. {
  1982. transaction->commit();
  1983. }
  1984. catch (IException *e)
  1985. {
  1986. StringBuffer eStr;
  1987. e->errorMessage(eStr);
  1988. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  1989. e->Release();
  1990. }
  1991. transaction.setown(createDistributedFileTransaction(user));
  1992. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  1993. transaction->start();
  1994. logctx.CTXLOG("Renaming regress::tenwayfile TO regress::rename3::sub2");
  1995. dir.renamePhysical("regress::tenwayfile@mythor", "regress::rename3::sub2", user, transaction);
  1996. try
  1997. {
  1998. transaction->commit();
  1999. }
  2000. catch (IException *e)
  2001. {
  2002. StringBuffer eStr;
  2003. e->errorMessage(eStr);
  2004. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  2005. e->Release();
  2006. }
  2007. }
  2008. void testDFSRemoveSuperSub()
  2009. {
  2010. setupDFS(logctx, "removesupersub");
  2011. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user);
  2012. logctx.CTXLOG("Creating regress::removesupersub::super1 and attaching sub1 & sub4");
  2013. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::removesupersub::super1", user, false, false, transaction);
  2014. sfile->addSubFile("regress::removesupersub::sub1", false, NULL, false, transaction);
  2015. sfile->addSubFile("regress::removesupersub::sub4", false, NULL, false, transaction);
  2016. sfile.clear();
  2017. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  2018. logctx.CTXLOG("Starting transaction");
  2019. transaction->start();
  2020. logctx.CTXLOG("Removing super removesupersub::super1 along with it's subfiles sub1 and sub4");
  2021. dir.removeSuperFile("regress::removesupersub::super1", true, user, transaction);
  2022. try
  2023. {
  2024. logctx.CTXLOG("Committing transaction");
  2025. transaction->commit();
  2026. }
  2027. catch (IException *e)
  2028. {
  2029. StringBuffer eStr;
  2030. e->errorMessage(eStr);
  2031. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  2032. e->Release();
  2033. }
  2034. transaction.clear();
  2035. // validate..
  2036. ASSERT(!dir.exists("regress::removesupersub::super1", user, true, false) && "regress::removesupersub::super1 should NOT exist");
  2037. ASSERT(!dir.exists("regress::removesupersub::sub1", user, true, false) && "regress::removesupersub::sub1 should NOT exist");
  2038. ASSERT(!dir.exists("regress::removesupersub::sub4", user, true, false) && "regress::removesupersub::sub4 should NOT exist");
  2039. }
  2040. };
  2041. CPPUNIT_TEST_SUITE_REGISTRATION( CDaliDFSTests );
  2042. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliDFSTests, "CDaliDFSTests" );
  2043. class CDaliDFSRetrySlowTests : public CppUnit::TestFixture
  2044. {
  2045. CPPUNIT_TEST_SUITE(CDaliDFSRetrySlowTests);
  2046. CPPUNIT_TEST(testInit);
  2047. CPPUNIT_TEST(testDFSAddFailReAdd);
  2048. CPPUNIT_TEST(testDFSRetrySuperLock);
  2049. CPPUNIT_TEST_SUITE_END();
  2050. const IContextLogger &logctx;
  2051. public:
  2052. CDaliDFSRetrySlowTests() : logctx(queryDummyContextLogger())
  2053. {
  2054. }
  2055. ~CDaliDFSRetrySlowTests()
  2056. {
  2057. daliClientEnd();
  2058. }
  2059. void testInit()
  2060. {
  2061. daliClientInit();
  2062. }
  2063. class CShortLock : implements IThreaded
  2064. {
  2065. StringAttr fileName;
  2066. unsigned secDelay;
  2067. CThreaded threaded;
  2068. public:
  2069. CShortLock(const char *_fileName, unsigned _secDelay) : fileName(_fileName), secDelay(_secDelay), threaded("CShortLock", this) { }
  2070. ~CShortLock()
  2071. {
  2072. threaded.join();
  2073. }
  2074. virtual void threadmain() override
  2075. {
  2076. Owned<IDistributedFile> file=queryDistributedFileDirectory().lookup(fileName, NULL);
  2077. if (!file)
  2078. {
  2079. PROGLOG("File %s not found", fileName.get());
  2080. return;
  2081. }
  2082. PROGLOG("Locked file: %s, sleeping (before unlock) for %d secs", fileName.get(), secDelay);
  2083. MilliSleep(secDelay * 1000);
  2084. PROGLOG("Unlocking file: %s", fileName.get());
  2085. }
  2086. void start() { threaded.start(); }
  2087. };
  2088. void testDFSAddFailReAdd()
  2089. {
  2090. setupDFS(logctx, "addreadd");
  2091. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  2092. logctx.CTXLOG("Creating super1 and supet2, adding sub1 and sub2 to super1 and sub3 to super2");
  2093. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::addreadd::super1", user, false, false, transaction);
  2094. sfile->addSubFile("regress::addreadd::sub1", false, NULL, false, transaction);
  2095. sfile->addSubFile("regress::addreadd::sub2", false, NULL, false, transaction);
  2096. sfile.clear();
  2097. Owned<IDistributedSuperFile> sfile2 = dir.createSuperFile("regress::addreadd::super2", user, false, false, transaction);
  2098. sfile2->addSubFile("regress::addreadd::sub3", false, NULL, false, transaction);
  2099. sfile2.clear();
  2100. /* Tests transaction failing, due to lock and retrying after having partial success */
  2101. CShortLock sL("regress::addreadd::sub2", 30); // the 2nd subfile of super1
  2102. sL.start();
  2103. transaction.setown(createDistributedFileTransaction(user)); // disabled, auto-commit
  2104. logctx.CTXLOG("Starting transaction");
  2105. transaction->start();
  2106. logctx.CTXLOG("Adding contents of regress::addreadd::super1 to regress::addreadd::super2, within transaction");
  2107. sfile.setown(transaction->lookupSuperFile("regress::addreadd::super2"));
  2108. sfile->addSubFile("regress::addreadd::super1", false, NULL, true, transaction); // add contents of super1 to super2
  2109. sfile.setown(transaction->lookupSuperFile("regress::addreadd::super1"));
  2110. sfile->removeSubFile(NULL, false, false, transaction); // clears super1
  2111. sfile.clear();
  2112. try
  2113. {
  2114. transaction->commit();
  2115. }
  2116. catch (IException *e)
  2117. {
  2118. StringBuffer eStr;
  2119. e->errorMessage(eStr);
  2120. CPPUNIT_ASSERT_MESSAGE(eStr.str(), 0);
  2121. e->Release();
  2122. }
  2123. transaction.clear();
  2124. sfile.setown(dir.lookupSuperFile("regress::addreadd::super2", user));
  2125. ASSERT(3 == sfile->numSubFiles() && "regress::addreadd::super2 should contain 3 subfiles");
  2126. ASSERT(NULL != sfile->querySubFileNamed("regress::addreadd::sub1") && "regress::addreadd::sub1, should be a subfile of super2");
  2127. ASSERT(NULL != sfile->querySubFileNamed("regress::addreadd::sub2") && "regress::addreadd::sub2, should be a subfile of super2");
  2128. ASSERT(NULL != sfile->querySubFileNamed("regress::addreadd::sub3") && "regress::addreadd::sub3, should be a subfile of super2");
  2129. sfile.setown(dir.lookupSuperFile("regress::addreadd::super1", user));
  2130. ASSERT(0 == sfile->numSubFiles() && "regress::addreadd::super1 should contain 0 subfiles");
  2131. }
  2132. void testDFSRetrySuperLock()
  2133. {
  2134. setupDFS(logctx, "retrysuperlock");
  2135. logctx.CTXLOG("Creating regress::retrysuperlock::super1 and regress::retrysuperlock::sub1");
  2136. Owned<IDistributedSuperFile> sfile = dir.createSuperFile("regress::retrysuperlock::super1", user, false, false);
  2137. sfile->addSubFile("regress::retrysuperlock::sub1", false, NULL, false);
  2138. sfile.clear();
  2139. /* Tests transaction failing, due to lock and retrying after having partial success */
  2140. CShortLock sL("regress::retrysuperlock::super1", 15);
  2141. sL.start();
  2142. sfile.setown(dir.lookupSuperFile("regress::retrysuperlock::super1", user));
  2143. if (sfile)
  2144. {
  2145. logctx.CTXLOG("Removing subfiles from regress::retrysuperlock::super1");
  2146. sfile->removeSubFile(NULL, false, false);
  2147. logctx.CTXLOG("SUCCEEDED");
  2148. }
  2149. // put it back, for next test
  2150. sfile->addSubFile("regress::retrysuperlock::sub1", false, NULL, false);
  2151. sfile.clear();
  2152. // try again, this time in transaction
  2153. Owned<IDistributedFileTransaction> transaction = createDistributedFileTransaction(user); // disabled, auto-commit
  2154. logctx.CTXLOG("Starting transaction");
  2155. transaction->start();
  2156. sfile.setown(transaction->lookupSuperFile("regress::retrysuperlock::super1"));
  2157. if (sfile)
  2158. {
  2159. logctx.CTXLOG("Removing subfiles from regress::retrysuperlock::super1 with transaction");
  2160. sfile->removeSubFile(NULL, false, false, transaction);
  2161. logctx.CTXLOG("SUCCEEDED");
  2162. }
  2163. sfile.clear();
  2164. logctx.CTXLOG("Committing transaction");
  2165. transaction->commit();
  2166. }
  2167. };
  2168. CPPUNIT_TEST_SUITE_REGISTRATION( CDaliDFSRetrySlowTests );
  2169. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliDFSRetrySlowTests, "CDaliDFSRetrySlowTests" );
  2170. class CDaliUtils : public CppUnit::TestFixture
  2171. {
  2172. CPPUNIT_TEST_SUITE(CDaliUtils);
  2173. CPPUNIT_TEST(testDFSLfn);
  2174. CPPUNIT_TEST_SUITE_END();
  2175. public:
  2176. void testDFSLfn()
  2177. {
  2178. const char *lfns[] = { "~foreign::192.168.16.1::scope1::file1",
  2179. "~file::192.168.16.1::dir1::file1",
  2180. "~file::192.168.16.1::>some query or another",
  2181. "~file::192.168.16.1::wild?card1",
  2182. "~file::192.168.16.1::wild*card2",
  2183. "~file::192.168.16.1::^C^a^S^e^d",
  2184. "~file::192.168.16.1::file@cluster1",
  2185. "~prefix::{multi1*,multi2*}",
  2186. "{~foreign::192.168.16.1::multi1, ~foreign::192.168.16.2::multi2}",
  2187. // NB: CDfsLogicalFileName allows these with strict=false (the default)
  2188. ". :: scope1 :: file",
  2189. ":: scope1 :: file",
  2190. "~ scope1 :: scope2 :: file ",
  2191. ". :: scope1 :: file nine",
  2192. ". :: scope1 :: file ten ",
  2193. ". :: scope1 :: file",
  2194. NULL // terminator
  2195. };
  2196. const char *invalidLfns[] = {
  2197. ". :: sc~ope1::file",
  2198. ". :: ::file",
  2199. "~~scope1::file",
  2200. "~sc~ope1::file2",
  2201. ".:: scope1::file*",
  2202. NULL // terminator
  2203. };
  2204. PROGLOG("Checking valid logical filenames");
  2205. unsigned nlfn=0;
  2206. for (;;)
  2207. {
  2208. const char *lfn = lfns[nlfn++];
  2209. if (NULL == lfn)
  2210. break;
  2211. PROGLOG("lfn = %s", lfn);
  2212. CDfsLogicalFileName dlfn;
  2213. try
  2214. {
  2215. dlfn.set(lfn);
  2216. }
  2217. catch (IException *e)
  2218. {
  2219. VStringBuffer err("Logical filename '%s' failed.", lfn);
  2220. EXCLOG(e, err.str());
  2221. CPPUNIT_FAIL(err.str());
  2222. e->Release();
  2223. }
  2224. }
  2225. PROGLOG("Checking invalid logical filenames");
  2226. nlfn = 0;
  2227. for (;;)
  2228. {
  2229. const char *lfn = invalidLfns[nlfn++];
  2230. if (NULL == lfn)
  2231. break;
  2232. PROGLOG("lfn = %s", lfn);
  2233. CDfsLogicalFileName dlfn;
  2234. try
  2235. {
  2236. dlfn.set(lfn);
  2237. VStringBuffer err("Logical filename '%s' passed and should have failed.", lfn);
  2238. ERRLOG("%s", err.str());
  2239. CPPUNIT_FAIL(err.str());
  2240. }
  2241. catch (IException *e)
  2242. {
  2243. EXCLOG(e, "Expected error:");
  2244. e->Release();
  2245. }
  2246. }
  2247. }
  2248. };
  2249. CPPUNIT_TEST_SUITE_REGISTRATION( CDaliUtils );
  2250. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CDaliUtils, "DaliUtils" );
  2251. class CFileNameNormalizeUnitTest : public CppUnit::TestFixture, CDfsLogicalFileName
  2252. {
  2253. CPPUNIT_TEST_SUITE(CFileNameNormalizeUnitTest);
  2254. CPPUNIT_TEST(testFileNameNormalize);
  2255. CPPUNIT_TEST_SUITE_END();
  2256. public:
  2257. void testFileNameNormalize()
  2258. {
  2259. //Columns
  2260. const int inFileName = 0;
  2261. const int normalizedFileName = 1;
  2262. const char *validExternalLfns[][2] = {
  2263. // input file name expected normalized file name
  2264. {"~file::192.168.16.1::dir1::file1", "file::192.168.16.1::dir1::file1"},
  2265. {"~ file:: 192.168.16.1::dir1::file1", "file::192.168.16.1::dir1::file1"},
  2266. {"~file::192.168.16.1::>some query or another", "file::192.168.16.1::>some query or another"},
  2267. {"~file::192.168.16.1::>Some Query or Another", "file::192.168.16.1::>Some Query or Another"},
  2268. {"~file::192.168.16.1::wild?card1", "file::192.168.16.1::wild?card1"},
  2269. {"~file::192.168.16.1::wild*card2", "file::192.168.16.1::wild*card2"},
  2270. {"~file::192.168.16.1::^C^a^S^e^d", "file::192.168.16.1::^c^a^s^e^d"},
  2271. {nullptr, nullptr } // terminator
  2272. };
  2273. const char *validInternalLfns[][2] = {
  2274. // input file name expected normalized file name
  2275. {"~foreign::192.168.16.1::scope1::file1", "foreign::192.168.16.1::scope1::file1"},
  2276. {".::scope1::file", ".::scope1::file"},
  2277. {"~ scope1 :: scope2 :: file ", "scope1::scope2::file"},
  2278. {". :: scope1 :: file nine", ".::scope1::file nine"},
  2279. {". :: scope1 :: file ten ", ".::scope1::file ten"},
  2280. {". :: scope1 :: file", ".::scope1::file"},
  2281. {"~scope1::file@cluster1", "scope1::file"},
  2282. {"~scope::^C^a^S^e^d", "scope::^c^a^s^e^d"},
  2283. {"~scope::CaSed", "scope::cased"},
  2284. {"~scope::^CaSed", "scope::^cased"},
  2285. {nullptr, nullptr} // terminator
  2286. };
  2287. // Check results
  2288. const bool externalFile = true;
  2289. const bool internalFile = false;
  2290. const bool fileNameMatch = true;
  2291. PROGLOG("Checking external filenames detection and normalization");
  2292. unsigned nlfn=0;
  2293. for (;;)
  2294. {
  2295. const char *lfn = validExternalLfns[nlfn][inFileName];
  2296. if (nullptr == lfn)
  2297. break;
  2298. PROGLOG("lfn = '%s'", lfn);
  2299. StringAttr res;
  2300. try
  2301. {
  2302. ASSERT(externalFile == normalizeExternal(lfn, res, false));
  2303. PROGLOG("res = '%s'", res.str());
  2304. ASSERT(fileNameMatch == streq(res.str(), validExternalLfns[nlfn][normalizedFileName]))
  2305. }
  2306. catch (IException *e)
  2307. {
  2308. VStringBuffer err("External filename '%s' ('%s') failed.", lfn, res.str());
  2309. EXCLOG(e, err.str());
  2310. e->Release();
  2311. CPPUNIT_FAIL(err.str());
  2312. }
  2313. nlfn++;
  2314. }
  2315. PROGLOG("Checking valid internal filenames");
  2316. nlfn=0;
  2317. for (;;)
  2318. {
  2319. const char *lfn = validInternalLfns[nlfn][inFileName];
  2320. if (nullptr == lfn)
  2321. break;
  2322. PROGLOG("lfn = '%s'", lfn);
  2323. StringAttr res;
  2324. try
  2325. {
  2326. ASSERT(internalFile == normalizeExternal(lfn, res, false));
  2327. normalizeName(lfn, res, false);
  2328. PROGLOG("res = '%s'", res.str());
  2329. ASSERT(fileNameMatch == streq(res.str(), validInternalLfns[nlfn][normalizedFileName]))
  2330. }
  2331. catch (IException *e)
  2332. {
  2333. VStringBuffer err("Internal filename '%s' ('%s') failed.", lfn, res.str());
  2334. EXCLOG(e, err.str());
  2335. e->Release();
  2336. CPPUNIT_FAIL(err.str());
  2337. }
  2338. nlfn++;
  2339. }
  2340. }
  2341. };
  2342. CPPUNIT_TEST_SUITE_REGISTRATION( CFileNameNormalizeUnitTest );
  2343. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( CFileNameNormalizeUnitTest, "CFileNameNormalizeUnitTest" );
  2344. #endif // _USE_CPPUNIT