esdltests.cpp 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267
  1. /*##############################################################################
  2. Copyright (C) 2020 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. #ifdef _USE_CPPUNIT
  14. #include "unittests.hpp"
  15. #include "espcontext.hpp"
  16. #include "xpathprocessor.hpp"
  17. #include "esdl_script.hpp"
  18. #include "wsexcept.hpp"
  19. #include <stdio.h>
  20. #include "dllserver.hpp"
  21. #include "thorplugin.hpp"
  22. #include "eclrtl.hpp"
  23. #include "rtlformat.hpp"
  24. // =============================================================== URI parser
  25. static constexpr const char * soapRequest = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  26. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  27. <soap:Body>
  28. <extra>
  29. <EchoPersonInfo>
  30. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  31. <Context>
  32. <Row>
  33. <Common>
  34. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  35. </Common>
  36. </Row>
  37. </Context>
  38. <EchoPersonInfoRequest>
  39. <Row>
  40. <Name>
  41. <First>Joe</First>
  42. <Last>Doe</Last>
  43. </Name>
  44. <Addresses>
  45. <Address>
  46. <type>Home</type>
  47. <Line1>101 Main street</Line1>
  48. <Line2>Apt 202</Line2>
  49. <City>Hometown</City>
  50. <State>HI</State>
  51. <Zip>96703</Zip>
  52. </Address>
  53. </Addresses>
  54. </Row>
  55. </EchoPersonInfoRequest>
  56. </EchoPersonInfo>
  57. </extra>
  58. </soap:Body>
  59. </soap:Envelope>
  60. )!!";
  61. static constexpr const char * esdlScript = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="soap:Body/extra/{$query}/{$request}">
  62. <es:variable name="var1" select="'script'"/>
  63. <es:variable name="var2" select="$var1"/>
  64. <es:param name='testcase' select="'unknown'"/>
  65. <es:param name='FailStrict' select='false()'/>
  66. <es:param name='FailLevel1A' select='false()'/>
  67. <es:param name='FailLevel1B' select='false()'/>
  68. <es:param name='AssertLevel1C' select='false()'/>
  69. <es:param name='FailLevel2A' select='false()'/>
  70. <es:param name='FailLevel2B' select='false()'/>
  71. <es:param name='AssertLevel2C' select='false()'/>
  72. <es:param name="param1" select="'script'"/>
  73. <es:param name="param2" select="$param1"/>
  74. <es:set-value target="TestCase" select="$testcase"/>
  75. <es:set-value target="Var2" select="$var2"/>
  76. <es:set-value target="Param2" select="$param2"/>
  77. <es:choose>
  78. <es:when test="not(es:validateFeaturesAccess('AllowSomething : Read, AllowAnother : Full'))">
  79. <es:fail code="401" message="concat('authorization failed for something or other (', $clientversion, ')')"/>
  80. </es:when>
  81. <es:when test="not(es:getFeatureSecAccessFlags('AllowSomething')=es:secureAccessFlags('Full'))">
  82. <es:fail code="401" message="concat('auth flag check failed for something (', $clientversion, ')')"/>
  83. </es:when>
  84. <es:when test="$FailStrict">
  85. <es:if test="$undeclared">
  86. <es:fail code="1" message="'not strict'"/>
  87. </es:if>
  88. </es:when>
  89. <es:when test="$FailLevel1A">
  90. <es:fail code="11" message="'FailLevel1A'"/>
  91. </es:when>
  92. <es:when test="$FailLevel1B">
  93. <es:if test="$FailLevel1B">
  94. <es:fail code="12" message="'FailLevel1B'"/>
  95. </es:if>
  96. </es:when>
  97. <es:when test="$AssertLevel1C">
  98. <es:assert test="not($AssertLevel1C)" code="13" message="'AssertLevel1C'"/>
  99. </es:when>
  100. <es:otherwise>
  101. <es:set-value target="InnerTestCase" select="$testcase"/>
  102. <es:choose>
  103. <es:when test="$FailLevel2A">
  104. <es:fail code="21" message="'FailLevel2A'"/>
  105. </es:when>
  106. <es:when test="$FailLevel2B">
  107. <es:if test="$FailLevel2B">
  108. <es:fail code="22" message="'FailLevel2B'"/>
  109. </es:if>
  110. </es:when>
  111. <es:when test="$AssertLevel2C">
  112. <es:assert test="not($AssertLevel2C)" code="23" message="'AssertLevel2C'"/>
  113. </es:when>
  114. <es:otherwise>
  115. <es:set-value target="test" select="'auth success'"/>
  116. <es:set-value target="Row/Name/Last" select="'XXX'"/>
  117. <es:set-value target="Row/Name/Last" select="'POE'"/>
  118. <es:append-to-value target="Row/AppendTo" select="'This'"/>
  119. <es:append-to-value target="Row/AppendTo" select="'One'"/>
  120. <es:append-to-value target="Row/AppendTo" select="'String'"/>
  121. <es:add-value target="Row/Name/Aliases/Alias" select="'moe'"/>
  122. <es:add-value target="Row/Name/Aliases/Alias" select="'poe'"/>
  123. <es:add-value target="Row/Name/Aliases/Alias" select="'roe'"/>
  124. </es:otherwise>
  125. </es:choose>
  126. </es:otherwise>
  127. </es:choose>
  128. </es:CustomRequestTransform>
  129. )!!";
  130. static constexpr const char * esdlScriptNoPrefix = R"!!(<CustomRequestTransform xmlns="urn:hpcc:esdl:script" target="soap:Body/extra/{$query}/{$request}">
  131. <variable name="var1" select="'script'"/>
  132. <variable name="var2" select="$var1"/>
  133. <param name='testcase' select="'unknown'"/>
  134. <param name='FailStrict' select='false()'/>
  135. <param name='FailLevel1A' select='false()'/>
  136. <param name='FailLevel1B' select='false()'/>
  137. <param name='AssertLevel1C' select='false()'/>
  138. <param name='FailLevel2A' select='false()'/>
  139. <param name='FailLevel2B' select='false()'/>
  140. <param name='AssertLevel2C' select='false()'/>
  141. <param name="param1" select="'script'"/>
  142. <param name="param2" select="$param1"/>
  143. <set-value target="TestCase" select="$testcase"/>
  144. <set-value target="Var2" select="$var2"/>
  145. <set-value target="Param2" select="$param2"/>
  146. <choose>
  147. <when test="not(validateFeaturesAccess('AllowSomething : Read, AllowAnother : Full'))">
  148. <fail code="401" message="concat('authorization failed for something or other (', $clientversion, ')')"/>
  149. </when>
  150. <when test="not(getFeatureSecAccessFlags('AllowSomething')=secureAccessFlags('Full'))">
  151. <fail code="401" message="concat('auth flag check failed for something (', $clientversion, ')')"/>
  152. </when>
  153. <when test="$FailStrict">
  154. <if test="$undeclared">
  155. <fail code="1" message="'not strict'"/>
  156. </if>
  157. </when>
  158. <when test="$FailLevel1A">
  159. <fail code="11" message="'FailLevel1A'"/>
  160. </when>
  161. <when test="$FailLevel1B">
  162. <if test="$FailLevel1B">
  163. <fail code="12" message="'FailLevel1B'"/>
  164. </if>
  165. </when>
  166. <when test="$AssertLevel1C">
  167. <assert test="not($AssertLevel1C)" code="13" message="'AssertLevel1C'"/>
  168. </when>
  169. <otherwise>
  170. <set-value target="InnerTestCase" select="$testcase"/>
  171. <choose>
  172. <when test="$FailLevel2A">
  173. <fail code="21" message="'FailLevel2A'"/>
  174. </when>
  175. <when test="$FailLevel2B">
  176. <if test="$FailLevel2B">
  177. <fail code="22" message="'FailLevel2B'"/>
  178. </if>
  179. </when>
  180. <when test="$AssertLevel2C">
  181. <assert test="not($AssertLevel2C)" code="23" message="'AssertLevel2C'"/>
  182. </when>
  183. <otherwise>
  184. <set-value target="test" select="'auth success'"/>
  185. <set-value target="Row/Name/Last" select="'XXX'"/>
  186. <set-value target="Row/Name/Last" select="'POE'"/>
  187. <append-to-value target="Row/AppendTo" select="'This'"/>
  188. <append-to-value target="Row/AppendTo" select="'One'"/>
  189. <append-to-value target="Row/AppendTo" select="'String'"/>
  190. <add-value target="Row/Name/Aliases/Alias" select="'moe'"/>
  191. <add-value target="Row/Name/Aliases/Alias" select="'poe'"/>
  192. <add-value target="Row/Name/Aliases/Alias" select="'roe'"/>
  193. </otherwise>
  194. </choose>
  195. </otherwise>
  196. </choose>
  197. </CustomRequestTransform>
  198. )!!";
  199. static constexpr const char * esdlScriptSelectPath = R"!!(
  200. <es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="soap:Body/extra/{$query}/{$request}">
  201. <es:param name="selectPath" select="''"/>
  202. <es:set-value target="_OUTPUT_" select="$selectPath"/>
  203. </es:CustomRequestTransform>
  204. )!!";
  205. static constexpr const char * esdlImplicitNamespaceSelectPath = R"!!(
  206. <es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="soap:Body/n:extra/n:{$query}/n:{$request}">
  207. <es:param name="selectPath" select="''"/>
  208. <es:set-value target="_OUTPUT_" select="$selectPath"/>
  209. </es:CustomRequestTransform>
  210. )!!";
  211. static constexpr const char* selectPathResult = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  212. <soap:Body>
  213. <extra>
  214. <EchoPersonInfo>
  215. <Context>
  216. <Row>
  217. <Common>
  218. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  219. </Common>
  220. </Row>
  221. </Context>
  222. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  223. <EchoPersonInfoRequest>
  224. <Row>
  225. <Addresses>
  226. <Address>
  227. <type>Home</type>
  228. <Line2>Apt 202</Line2>
  229. <Line1>101 Main street</Line1>
  230. <City>Hometown</City>
  231. <Zip>96703</Zip>
  232. <State>HI</State>
  233. </Address>
  234. </Addresses>
  235. <Name>
  236. <Last>Doe</Last>
  237. <First>Joe</First>
  238. </Name>
  239. </Row>
  240. <_OUTPUT_>Joe</_OUTPUT_>
  241. </EchoPersonInfoRequest>
  242. </EchoPersonInfo>
  243. </extra>
  244. </soap:Body>
  245. </soap:Envelope>)!!";
  246. bool areEquivalentTestXMLStrings(const char *xml1, const char *xml2)
  247. {
  248. if (isEmptyString(xml1) || isEmptyString(xml2))
  249. return false;
  250. Owned<IPropertyTree> tree1 = createPTreeFromXMLString(xml1);
  251. Owned<IPropertyTree> tree2 = createPTreeFromXMLString(xml2);
  252. return areMatchingPTrees(tree1, tree2);
  253. }
  254. static const char *target_config = "<method queryname='EchoPersonInfo'/>";
  255. class ESDLTests : public CppUnit::TestFixture
  256. {
  257. CPPUNIT_TEST_SUITE( ESDLTests );
  258. CPPUNIT_TEST(testEsdlTransformScript);
  259. CPPUNIT_TEST(testEsdlTransformScriptNoPrefix);
  260. CPPUNIT_TEST(testEsdlTransformForEach);
  261. CPPUNIT_TEST(testEsdlTransformVarScope);
  262. CPPUNIT_TEST(testEsdlTransformLegacy);
  263. CPPUNIT_TEST(testEsdlTransformIgnoreScriptErrors);
  264. CPPUNIT_TEST(testEsdlTransformTargetXpathErrors);
  265. CPPUNIT_TEST(testEsdlTransformFailStrict);
  266. CPPUNIT_TEST(testEsdlTransformScriptVarParam);
  267. CPPUNIT_TEST(testEsdlTransformFailLevel1A);
  268. CPPUNIT_TEST(testEsdlTransformFailLevel1B);
  269. CPPUNIT_TEST(testEsdlTransformFailLevel1C);
  270. CPPUNIT_TEST(testEsdlTransformFailLevel2A);
  271. CPPUNIT_TEST(testEsdlTransformFailLevel2B);
  272. CPPUNIT_TEST(testEsdlTransformFailLevel2C);
  273. CPPUNIT_TEST(testEsdlTransformAnyDescendentPath);
  274. CPPUNIT_TEST(testEsdlTransformAbsoluteSoapPath);
  275. CPPUNIT_TEST(testEsdlTransformRelativePath);
  276. CPPUNIT_TEST(testEsdlTransformSelectPath);
  277. CPPUNIT_TEST(testEsdlTransformImplicitPrefix);
  278. CPPUNIT_TEST(testEsdlTransformRequestNamespaces);
  279. CPPUNIT_TEST(testScriptContext);
  280. CPPUNIT_TEST(testTargetElement);
  281. //The following require setup, uncomment for development testing for now:
  282. //CPPUNIT_TEST(testMysql);
  283. //CPPUNIT_TEST(testScriptMap); //requires a particular roxie query
  284. //CPPUNIT_TEST(testHTTPPostXml); //requires a particular roxie query
  285. CPPUNIT_TEST_SUITE_END();
  286. public:
  287. ESDLTests(){}
  288. inline const char *queryTestName(IPropertyTree *cfg)
  289. {
  290. const char *testname = cfg->queryProp("Transform/Param[@name='testcase']/@value");
  291. if (!testname)
  292. return "unknown";
  293. return testname;
  294. }
  295. IEsdlScriptContext *createTestScriptContext(IEspContext *ctx, const char *xml, const char *config)
  296. {
  297. Owned<IEsdlScriptContext> scriptContext = createEsdlScriptContext(ctx);
  298. scriptContext->setAttribute(ESDLScriptCtxSection_ESDLInfo, "service", "EsdlExample");
  299. scriptContext->setAttribute(ESDLScriptCtxSection_ESDLInfo, "method", "EchoPersonInfo");
  300. scriptContext->setAttribute(ESDLScriptCtxSection_ESDLInfo, "request_type", "EchoPersonInfoRequest");
  301. scriptContext->setAttribute(ESDLScriptCtxSection_ESDLInfo, "request", "EchoPersonInfoRequest");
  302. scriptContext->setContent(ESDLScriptCtxSection_BindingConfig, config);
  303. scriptContext->setContent(ESDLScriptCtxSection_TargetConfig, target_config);
  304. scriptContext->setContent(ESDLScriptCtxSection_ESDLRequest, xml);
  305. return scriptContext.getClear();
  306. }
  307. void runTransform(IEsdlScriptContext *scriptContext, const char *scriptXml, const char *srcSection, const char *tgtSection, const char *testname, int code)
  308. {
  309. Owned<IEsdlCustomTransform> tf = createEsdlCustomTransform(scriptXml, nullptr);
  310. tf->processTransform(scriptContext, srcSection, tgtSection);
  311. if (code)
  312. throw MakeStringException(99, "Test failed(%s): expected an explicit exception %d", testname, code);
  313. }
  314. void runTest(const char *testname, const char *scriptXml, const char *xml, const char *config, const char *result, int code)
  315. {
  316. try
  317. {
  318. //printf("starting %s:\n", testname); //uncomment to help debug
  319. Owned<IEspContext> ctx = createEspContext(nullptr);
  320. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, xml, config);
  321. runTransform(scriptContext, scriptXml, ESDLScriptCtxSection_ESDLRequest, ESDLScriptCtxSection_FinalRequest, testname, code);
  322. StringBuffer output;
  323. scriptContext->toXML(output.clear(), ESDLScriptCtxSection_FinalRequest);
  324. if (result && !areEquivalentTestXMLStrings(result, output.str()))
  325. {
  326. fputs(output.str(), stdout);
  327. fflush(stdout);
  328. fprintf(stdout, "\nTest failed(%s)\n", testname);
  329. CPPUNIT_ASSERT(false);
  330. }
  331. }
  332. catch (IException *E)
  333. {
  334. StringBuffer m;
  335. if (code!=E->errorCode())
  336. {
  337. StringBuffer m;
  338. fprintf(stdout, "\nTest(%s) Expected %d Exception %d - %s\n", testname, code, E->errorCode(), E->errorMessage(m).str());
  339. E->Release();
  340. CPPUNIT_ASSERT(false);
  341. }
  342. E->Release();
  343. }
  344. }
  345. void testEsdlTransformSelectPath()
  346. {
  347. constexpr const char* config = R"!!(
  348. <config strictParams='true'>
  349. <Transform>
  350. <Param name='testcase' value="select-path"/>
  351. <Param name='selectPath' select="//First"/>
  352. </Transform>
  353. </config>
  354. )!!";
  355. runTest("select-path", esdlScriptSelectPath, soapRequest, config, selectPathResult, 0);
  356. }
  357. void testEsdlTransformAbsoluteSoapPath()
  358. {
  359. constexpr const char* config = R"!!(
  360. <config strictParams='true'>
  361. <Transform>
  362. <Param name='testcase' value="absolute-soap-path"/>
  363. <Param name='selectPath' select="/esdl_script_context/esdl_request/soap:Envelope/soap:Body/extra/EchoPersonInfo/EchoPersonInfoRequest/Row/Name/First"/>
  364. </Transform>
  365. </config>
  366. )!!";
  367. runTest("absolute-soap-path", esdlScriptSelectPath, soapRequest, config, selectPathResult, 0);
  368. }
  369. void testEsdlTransformRelativePath()
  370. {
  371. constexpr const char* config = R"!!(
  372. <config strictParams='true'>
  373. <Transform>
  374. <Param name='testcase' value="relative-path"/>
  375. <Param name='selectPath' select="soap:Body/extra/EchoPersonInfo/EchoPersonInfoRequest/Row/Name/First"/>
  376. </Transform>
  377. </config>
  378. )!!";
  379. runTest("relative-path", esdlScriptSelectPath, soapRequest, config, selectPathResult, 0);
  380. }
  381. void testEsdlTransformAnyDescendentPath()
  382. {
  383. constexpr const char* config = R"!!(
  384. <config strictParams='true'>
  385. <Transform>
  386. <Param name='testcase' value="any-descendent-path"/>
  387. <Param name='selectPath' select="//First"/>
  388. </Transform>
  389. </config>
  390. )!!";
  391. runTest("any-descendent-path", esdlScriptSelectPath, soapRequest, config, selectPathResult, 0);
  392. }
  393. void testEsdlTransformImplicitPrefix()
  394. {
  395. static constexpr const char * soapRequestImplicitPrefix = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  396. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://webservices.example.com/WsFooBar">
  397. <soap:Body>
  398. <extra>
  399. <EchoPersonInfo>
  400. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  401. <Context>
  402. <Row>
  403. <Common>
  404. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  405. </Common>
  406. </Row>
  407. </Context>
  408. <EchoPersonInfoRequest>
  409. <Row>
  410. <Name>
  411. <First>Joe</First>
  412. <Last>Doe</Last>
  413. </Name>
  414. <Addresses>
  415. <Address>
  416. <type>Home</type>
  417. <Line1>101 Main street</Line1>
  418. <Line2>Apt 202</Line2>
  419. <City>Hometown</City>
  420. <State>HI</State>
  421. <Zip>96703</Zip>
  422. </Address>
  423. </Addresses>
  424. </Row>
  425. </EchoPersonInfoRequest>
  426. </EchoPersonInfo>
  427. </extra>
  428. </soap:Body>
  429. </soap:Envelope>
  430. )!!";
  431. constexpr const char* implicitPrefixResult = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://webservices.example.com/WsFooBar">
  432. <soap:Body>
  433. <extra>
  434. <EchoPersonInfo>
  435. <Context>
  436. <Row>
  437. <Common>
  438. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  439. </Common>
  440. </Row>
  441. </Context>
  442. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  443. <EchoPersonInfoRequest>
  444. <Row>
  445. <Addresses>
  446. <Address>
  447. <type>Home</type>
  448. <Line2>Apt 202</Line2>
  449. <Line1>101 Main street</Line1>
  450. <City>Hometown</City>
  451. <Zip>96703</Zip>
  452. <State>HI</State>
  453. </Address>
  454. </Addresses>
  455. <Name>
  456. <Last>Doe</Last>
  457. <First>Joe</First>
  458. </Name>
  459. </Row>
  460. <_OUTPUT_>Joe</_OUTPUT_>
  461. </EchoPersonInfoRequest>
  462. </EchoPersonInfo>
  463. </extra>
  464. </soap:Body>
  465. </soap:Envelope>)!!";
  466. constexpr const char* config = R"!!(
  467. <config strictParams='true'>
  468. <Transform>
  469. <Param name='testcase' value="implicit-prefix"/>
  470. <Param name='selectPath' select="soap:Body/n:extra/n:EchoPersonInfo/n:EchoPersonInfoRequest/n:Row/n:Name/n:First"/>
  471. </Transform>
  472. </config>
  473. )!!";
  474. constexpr const char* configNoPrefix = R"!!(
  475. <config strictParams='true'>
  476. <Transform>
  477. <Param name='testcase' value="implicit-prefix-not-used"/>
  478. <Param name='selectPath' select="soap:Body/extra/EchoPersonInfo/EchoPersonInfoRequest/Row/Name/First"/>
  479. </Transform>
  480. </config>
  481. )!!";
  482. runTest("implicit-prefix", esdlImplicitNamespaceSelectPath, soapRequestImplicitPrefix, config, implicitPrefixResult, 0);
  483. // The implicit 'n' prefix is required if the content has a namespace defined
  484. // with no prefix. This test is expected to throw an exception.
  485. runTest("implicit-prefix-not-used", esdlImplicitNamespaceSelectPath, soapRequestImplicitPrefix, configNoPrefix, implicitPrefixResult, 99);
  486. }
  487. void testEsdlTransformRequestNamespaces()
  488. {
  489. static constexpr const char * soapRequestNsInvalid = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  490. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="invalid.uri.string">
  491. <soap:Body>
  492. <extra>
  493. <EchoPersonInfo>
  494. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  495. <Context>
  496. <Row>
  497. <Common>
  498. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  499. </Common>
  500. </Row>
  501. </Context>
  502. <EchoPersonInfoRequest>
  503. <Row>
  504. <Name>
  505. <First>Joe</First>
  506. <Last>Doe</Last>
  507. </Name>
  508. </Row>
  509. </EchoPersonInfoRequest>
  510. </EchoPersonInfo>
  511. </extra>
  512. </soap:Body>
  513. </soap:Envelope>
  514. )!!";
  515. static constexpr const char * soapRequestNsArbitrary1 = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  516. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="arbitary:urn:text.here?really">
  517. <soap:Body>
  518. <extra>
  519. <EchoPersonInfo>
  520. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  521. <Context>
  522. <Row>
  523. <Common>
  524. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  525. </Common>
  526. </Row>
  527. </Context>
  528. <EchoPersonInfoRequest>
  529. <Row>
  530. <Name>
  531. <First>Joe</First>
  532. <Last>Doe</Last>
  533. </Name>
  534. </Row>
  535. </EchoPersonInfoRequest>
  536. </EchoPersonInfo>
  537. </extra>
  538. </soap:Body>
  539. </soap:Envelope>
  540. )!!";
  541. static constexpr const char * soapRequestNsArbitrary2 = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  542. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http:hullabaloo//nonsense:foo:bar#fragment">
  543. <soap:Body>
  544. <extra>
  545. <EchoPersonInfo>
  546. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  547. <Context>
  548. <Row>
  549. <Common>
  550. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  551. </Common>
  552. </Row>
  553. </Context>
  554. <EchoPersonInfoRequest>
  555. <Row>
  556. <Name>
  557. <First>Joe</First>
  558. <Last>Doe</Last>
  559. </Name>
  560. </Row>
  561. </EchoPersonInfoRequest>
  562. </EchoPersonInfo>
  563. </extra>
  564. </soap:Body>
  565. </soap:Envelope>
  566. )!!";
  567. constexpr const char* namespaceResult = R"!!(<soap:Envelope xmlns="http://webservices.example.com/WsFooBar" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  568. <soap:Body>
  569. <extra>
  570. <EchoPersonInfo>
  571. <Context>
  572. <Row>
  573. <Common>
  574. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  575. </Common>
  576. </Row>
  577. </Context>
  578. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  579. <EchoPersonInfoRequest>
  580. <Row>
  581. <Name>
  582. <Last>Doe</Last>
  583. <First>Joe</First>
  584. </Name>
  585. </Row>
  586. <_OUTPUT_>Joe</_OUTPUT_>
  587. </EchoPersonInfoRequest>
  588. </EchoPersonInfo>
  589. </extra>
  590. </soap:Body>
  591. </soap:Envelope>
  592. )!!";
  593. constexpr const char* namespaceResultArbitrary1 = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="arbitary:urn:text.here?really">
  594. <soap:Body>
  595. <extra>
  596. <EchoPersonInfo>
  597. <Context>
  598. <Row>
  599. <Common>
  600. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  601. </Common>
  602. </Row>
  603. </Context>
  604. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  605. <EchoPersonInfoRequest>
  606. <Row>
  607. <Name>
  608. <Last>Doe</Last>
  609. <First>Joe</First>
  610. </Name>
  611. </Row>
  612. <_OUTPUT_>Joe</_OUTPUT_>
  613. </EchoPersonInfoRequest>
  614. </EchoPersonInfo>
  615. </extra>
  616. </soap:Body>
  617. </soap:Envelope>)!!";
  618. constexpr const char* namespaceResultArbitrary2 = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http:hullabaloo//nonsense:foo:bar#fragment">
  619. <soap:Body>
  620. <extra>
  621. <EchoPersonInfo>
  622. <Context>
  623. <Row>
  624. <Common>
  625. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  626. </Common>
  627. </Row>
  628. </Context>
  629. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  630. <EchoPersonInfoRequest>
  631. <Row>
  632. <Name>
  633. <Last>Doe</Last>
  634. <First>Joe</First>
  635. </Name>
  636. </Row>
  637. <_OUTPUT_>Joe</_OUTPUT_>
  638. </EchoPersonInfoRequest>
  639. </EchoPersonInfo>
  640. </extra>
  641. </soap:Body>
  642. </soap:Envelope>)!!";
  643. constexpr const char* configInvalidURI = R"!!(
  644. <config strictParams='true'>
  645. <Transform>
  646. <Param name='testcase' value="invalid-uri"/>
  647. <Param name='selectPath' select="soap:Body/n:extra/n:EchoPersonInfo/n:EchoPersonInfoRequest/n:Row/n:Name/n:First"/>
  648. </Transform>
  649. </config>
  650. )!!";
  651. constexpr const char* configArbitraryURI1 = R"!!(
  652. <config strictParams='true'>
  653. <Transform>
  654. <Param name='testcase' value="arbitrary-uri-1"/>
  655. <Param name='selectPath' select="soap:Body/n:extra/n:EchoPersonInfo/n:EchoPersonInfoRequest/n:Row/n:Name/n:First"/>
  656. </Transform>
  657. </config>
  658. )!!";
  659. constexpr const char* configArbitraryURI2 = R"!!(
  660. <config strictParams='true'>
  661. <Transform>
  662. <Param name='testcase' value="arbitrary-uri-2"/>
  663. <Param name='selectPath' select="soap:Body/n:extra/n:EchoPersonInfo/n:EchoPersonInfoRequest/n:Row/n:Name/n:First"/>
  664. </Transform>
  665. </config>
  666. )!!";
  667. // An invalid namespace URI that is expected to throw an exception
  668. runTest("invalid-uri", esdlScriptSelectPath, soapRequestNsInvalid, configInvalidURI, namespaceResult, 5684);
  669. // Weird but valid URIs for namespaces
  670. runTest("arbitrary-uri-1", esdlImplicitNamespaceSelectPath, soapRequestNsArbitrary1, configArbitraryURI1, namespaceResultArbitrary1, 0);
  671. runTest("arbitrary-uri-2", esdlImplicitNamespaceSelectPath, soapRequestNsArbitrary2, configArbitraryURI2, namespaceResultArbitrary2, 0);
  672. }
  673. void testEsdlTransformScript()
  674. {
  675. constexpr const char *config = R"!!(<config strictParams='true'>
  676. <Transform>
  677. <Param name='testcase' value="operations"/>
  678. </Transform>
  679. </config>)!!";
  680. constexpr const char * result = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  681. <soap:Body>
  682. <extra>
  683. <EchoPersonInfo>
  684. <Context>
  685. <Row>
  686. <Common>
  687. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  688. </Common>
  689. </Row>
  690. </Context>
  691. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  692. <EchoPersonInfoRequest>
  693. <InnerTestCase>operations</InnerTestCase>
  694. <TestCase>operations</TestCase>
  695. <Var2>script</Var2>
  696. <Row>
  697. <Addresses>
  698. <Address>
  699. <type>Home</type>
  700. <Line2>Apt 202</Line2>
  701. <Line1>101 Main street</Line1>
  702. <City>Hometown</City>
  703. <Zip>96703</Zip>
  704. <State>HI</State>
  705. </Address>
  706. </Addresses>
  707. <Name>
  708. <Last>POE</Last>
  709. <Aliases>
  710. <Alias>moe</Alias>
  711. <Alias>poe</Alias>
  712. <Alias>roe</Alias>
  713. </Aliases>
  714. <First>Joe</First>
  715. </Name>
  716. <AppendTo>ThisOneString</AppendTo>
  717. </Row>
  718. <test>auth success</test>
  719. <Param2>script</Param2>
  720. </EchoPersonInfoRequest>
  721. </EchoPersonInfo>
  722. </extra>
  723. </soap:Body>
  724. </soap:Envelope>)!!";
  725. runTest("operations", esdlScript, soapRequest, config, result, 0);
  726. }
  727. void testEsdlTransformScriptNoPrefix()
  728. {
  729. constexpr const char *config = R"!!(<config strictParams='true'>
  730. <Transform>
  731. <Param name='testcase' value="noprefix"/>
  732. </Transform>
  733. </config>)!!";
  734. constexpr const char * result = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  735. <soap:Body>
  736. <extra>
  737. <EchoPersonInfo>
  738. <Context>
  739. <Row>
  740. <Common>
  741. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  742. </Common>
  743. </Row>
  744. </Context>
  745. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  746. <EchoPersonInfoRequest>
  747. <TestCase>noprefix</TestCase>
  748. <InnerTestCase>noprefix</InnerTestCase>
  749. <Var2>script</Var2>
  750. <Row>
  751. <Addresses>
  752. <Address>
  753. <type>Home</type>
  754. <Line2>Apt 202</Line2>
  755. <Line1>101 Main street</Line1>
  756. <City>Hometown</City>
  757. <Zip>96703</Zip>
  758. <State>HI</State>
  759. </Address>
  760. </Addresses>
  761. <Name>
  762. <Last>POE</Last>
  763. <Aliases>
  764. <Alias>moe</Alias>
  765. <Alias>poe</Alias>
  766. <Alias>roe</Alias>
  767. </Aliases>
  768. <First>Joe</First>
  769. </Name>
  770. <AppendTo>ThisOneString</AppendTo>
  771. </Row>
  772. <Param2>script</Param2>
  773. <test>auth success</test>
  774. </EchoPersonInfoRequest>
  775. </EchoPersonInfo>
  776. </extra>
  777. </soap:Body>
  778. </soap:Envelope>)!!";
  779. runTest("noprefix", esdlScriptNoPrefix, soapRequest, config, result, 0);
  780. }
  781. void testEsdlTransformFailStrict()
  782. {
  783. constexpr const char *config = R"!!(<config strictParams='true'>
  784. <Transform>
  785. <Param name='testcase' value="fail strict"/>
  786. <Param name='FailStrict' select='true()'/>
  787. <Param name='undeclared' value='inaccessible'/>
  788. </Transform>
  789. </config>)!!";
  790. runTest("fail strict", esdlScript, soapRequest, config, nullptr, 5682);
  791. constexpr const char *config2 = R"!!(<config strictParams='false'>
  792. <Transform>
  793. <Param name='testcase' value="not strict"/>
  794. <Param name='FailStrict' select='true()'/>
  795. <Param name='undeclared' select='true()'/>
  796. </Transform>
  797. </config>)!!";
  798. runTest("not strict", esdlScript, soapRequest, config2, nullptr, 1);
  799. }
  800. void testEsdlTransformScriptVarParam()
  801. {
  802. constexpr const char *config = R"!!(<config strictParams='true'>
  803. <Transform>
  804. <Param name='testcase' value="varparam"/>
  805. <Param name='FailLevel1A' select='false()'/>
  806. <Param name='FailLevel1B' select='false()'/>
  807. <Param name='AssertLevel1C' select='false()'/>
  808. <Param name='FailLevel2A' select='false()'/>
  809. <Param name='FailLevel2B' select='false()'/>
  810. <Param name='AssertLevel2C' select='false()'/>
  811. <Param name='param1' value='provided'/>
  812. <Param name='param2' select="concat('produced and ', $param1)"/>
  813. <Param name='var1' value='provided'/>
  814. <Param name='var2' select="concat('produced and ', $var1)"/>
  815. </Transform>
  816. </config>)!!";
  817. constexpr const char * result = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  818. <soap:Body>
  819. <extra>
  820. <EchoPersonInfo>
  821. <Context>
  822. <Row>
  823. <Common>
  824. <TransactionId>1736623372_3126765312_1333296170</TransactionId>
  825. </Common>
  826. </Row>
  827. </Context>
  828. <_TransactionId>1736623372_3126765312_1333296170</_TransactionId>
  829. <EchoPersonInfoRequest>
  830. <InnerTestCase>varparam</InnerTestCase>
  831. <TestCase>varparam</TestCase>
  832. <Var2>script</Var2>
  833. <Row>
  834. <Addresses>
  835. <Address>
  836. <type>Home</type>
  837. <Line2>Apt 202</Line2>
  838. <Line1>101 Main street</Line1>
  839. <City>Hometown</City>
  840. <Zip>96703</Zip>
  841. <State>HI</State>
  842. </Address>
  843. </Addresses>
  844. <Name>
  845. <Last>POE</Last>
  846. <Aliases>
  847. <Alias>moe</Alias>
  848. <Alias>poe</Alias>
  849. <Alias>roe</Alias>
  850. </Aliases>
  851. <First>Joe</First>
  852. </Name>
  853. <AppendTo>ThisOneString</AppendTo>
  854. </Row>
  855. <test>auth success</test>
  856. <Param2>produced and provided</Param2>
  857. </EchoPersonInfoRequest>
  858. </EchoPersonInfo>
  859. </extra>
  860. </soap:Body>
  861. </soap:Envelope>)!!";
  862. runTest("fail strict", esdlScript, soapRequest, config, result, 0);
  863. }
  864. void testEsdlTransformForEach()
  865. {
  866. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  867. <root xmlns:xx1="urn:x1" xmlns:xx2="urn:x2">
  868. <extra>
  869. <Friends>
  870. <Name>
  871. <First>Joe</First>
  872. <xx1:Alias>Moe</xx1:Alias>
  873. <xx1:Alias>Poe</xx1:Alias>
  874. <xx1:Alias>Doe</xx1:Alias>
  875. </Name>
  876. <Name>
  877. <First>Jane</First>
  878. <xx1:Alias>Jan</xx1:Alias>
  879. <xx1:Alias>Janie</xx1:Alias>
  880. <xx1:Alias>Janet</xx1:Alias>
  881. </Name>
  882. </Friends>
  883. <Relatives>
  884. <Name>
  885. <First>Jonathon</First>
  886. <xx1:Alias>John</xx1:Alias>
  887. <xx1:Alias>Jon</xx1:Alias>
  888. <xx1:Alias>Johnny</xx1:Alias>
  889. <xx1:Alias>Johnnie</xx1:Alias>
  890. </Name>
  891. <Name>
  892. <First>Jennifer</First>
  893. <xx1:Alias>Jen</xx1:Alias>
  894. <xx1:Alias>Jenny</xx1:Alias>
  895. <xx1:Alias>Jenna</xx1:Alias>
  896. </Name>
  897. </Relatives>
  898. </extra>
  899. </root>
  900. )!!";
  901. static constexpr const char * forEachScript = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" xmlns:x1="urn:x1" xmlns:x2="urn:x2" target="extra">
  902. <es:param name="ForBuildListPath"/>
  903. <es:param name="ForIdPath"/>
  904. <es:param name="section"/>
  905. <es:param name="garbage"/>
  906. <es:for-each select="$ForBuildListPath">
  907. <es:variable name="q" select="str:decode-uri('%27')"/>
  908. <es:variable name="path" select="concat($section, '/Name[First=', $q, First, $q, ']/Aliases', $garbage)"/>
  909. <es:for-each select="x1:Alias">
  910. <es:choose>
  911. <es:when test="position()=1">
  912. <es:append-to-value xpath_target="$path" select="."/>
  913. </es:when>
  914. <es:otherwise>
  915. <es:append-to-value xpath_target="$path" select="','"/>
  916. <es:append-to-value xpath_target="$path" select="."/>
  917. </es:otherwise>
  918. </es:choose>
  919. </es:for-each>
  920. </es:for-each>
  921. <es:for-each select="$ForIdPath">
  922. <es:add-value target="People/Ids/Id" select="."/>
  923. </es:for-each>
  924. </es:CustomRequestTransform>
  925. )!!";
  926. constexpr const char * resultFriends = R"!!(<root xmlns:xx1="urn:x1" xmlns:xx2="urn:x2">
  927. <extra>
  928. <Relatives>
  929. <Name>
  930. <First>Jonathon</First>
  931. <xx1:Alias>John</xx1:Alias>
  932. <xx1:Alias>Jon</xx1:Alias>
  933. <xx1:Alias>Johnny</xx1:Alias>
  934. <xx1:Alias>Johnnie</xx1:Alias>
  935. </Name>
  936. <Name>
  937. <First>Jennifer</First>
  938. <xx1:Alias>Jen</xx1:Alias>
  939. <xx1:Alias>Jenny</xx1:Alias>
  940. <xx1:Alias>Jenna</xx1:Alias>
  941. </Name>
  942. </Relatives>
  943. <People>
  944. <Ids>
  945. <Id>Joe</Id>
  946. <Id>Jane</Id>
  947. </Ids>
  948. </People>
  949. <Friends>
  950. <Name>
  951. <Aliases>Moe,Poe,Doe</Aliases>
  952. <First>Joe</First>
  953. <xx1:Alias>Moe</xx1:Alias>
  954. <xx1:Alias>Poe</xx1:Alias>
  955. <xx1:Alias>Doe</xx1:Alias>
  956. </Name>
  957. <Name>
  958. <Aliases>Jan,Janie,Janet</Aliases>
  959. <First>Jane</First>
  960. <xx1:Alias>Jan</xx1:Alias>
  961. <xx1:Alias>Janie</xx1:Alias>
  962. <xx1:Alias>Janet</xx1:Alias>
  963. </Name>
  964. </Friends>
  965. </extra>
  966. </root>)!!";
  967. constexpr const char *configFriends = R"!!(<config strictParams="true">
  968. <Transform>
  969. <Param name='testcase' value="for each friend"/>
  970. <Param name='section' select="'Friends'"/>
  971. <Param name='garbage' select="''"/>
  972. <Param name='ForBuildListPath' select='/esdl_script_context/esdl_request/root/extra/Friends/Name'/>
  973. <Param name='ForIdPath' select='extra/Friends/Name/First'/>
  974. </Transform>
  975. </config>)!!";
  976. runTest("for each friend", forEachScript, input, configFriends, resultFriends, 0);
  977. constexpr const char * resultRelatives = R"!!(<root xmlns:xx1="urn:x1" xmlns:xx2="urn:x2">
  978. <extra>
  979. <Relatives>
  980. <Name>
  981. <Aliases>John,Jon,Johnny,Johnnie</Aliases>
  982. <First>Jonathon</First>
  983. <xx1:Alias>John</xx1:Alias>
  984. <xx1:Alias>Jon</xx1:Alias>
  985. <xx1:Alias>Johnny</xx1:Alias>
  986. <xx1:Alias>Johnnie</xx1:Alias>
  987. </Name>
  988. <Name>
  989. <Aliases>Jen,Jenny,Jenna</Aliases>
  990. <First>Jennifer</First>
  991. <xx1:Alias>Jen</xx1:Alias>
  992. <xx1:Alias>Jenny</xx1:Alias>
  993. <xx1:Alias>Jenna</xx1:Alias>
  994. </Name>
  995. </Relatives>
  996. <People>
  997. <Ids>
  998. <Id>Jonathon</Id>
  999. <Id>Jennifer</Id>
  1000. </Ids>
  1001. </People>
  1002. <Friends>
  1003. <Name>
  1004. <First>Joe</First>
  1005. <xx1:Alias>Moe</xx1:Alias>
  1006. <xx1:Alias>Poe</xx1:Alias>
  1007. <xx1:Alias>Doe</xx1:Alias>
  1008. </Name>
  1009. <Name>
  1010. <First>Jane</First>
  1011. <xx1:Alias>Jan</xx1:Alias>
  1012. <xx1:Alias>Janie</xx1:Alias>
  1013. <xx1:Alias>Janet</xx1:Alias>
  1014. </Name>
  1015. </Friends>
  1016. </extra>
  1017. </root>)!!";
  1018. constexpr const char *configRelatives = R"!!(<config strictParams="true">
  1019. <Transform>
  1020. <Param name='testcase' value="for each relative"/>
  1021. <Param name='section' select="'Relatives'"/>
  1022. <Param name='garbage' select="''"/>
  1023. <Param name='ForBuildListPath' select='extra/Relatives/Name'/>
  1024. <Param name='ForIdPath' select='/esdl_script_context/esdl_request/root/extra/Relatives/Name/First'/> <!--absolute path may change, highly frowned upon-->
  1025. </Transform>
  1026. </config>)!!";
  1027. runTest("for each relative", forEachScript, input, configRelatives, resultRelatives, 0);
  1028. constexpr const char *configGarbagePathError = R"!!(<config strictParams="true">
  1029. <Transform>
  1030. <Param name='testcase' value="for each garbage path error"/>
  1031. <Param name='section' select="'Friends'"/>
  1032. <Param name='garbage' select="'##'"/>
  1033. <Param name='ForBuildListPath' select='extra/Friends/Name'/>
  1034. <Param name='ForIdPath' select='extra/Friends/Name/First'/>
  1035. </Transform>
  1036. </config>)!!";
  1037. runTest("for each garbage path error", forEachScript, input, configGarbagePathError, nullptr, 5682);
  1038. constexpr const char * resultNada = R"!!(<root xmlns:xx1="urn:x1" xmlns:xx2="urn:x2">
  1039. <extra>
  1040. <Relatives>
  1041. <Name>
  1042. <First>Jonathon</First>
  1043. <xx1:Alias>John</xx1:Alias>
  1044. <xx1:Alias>Jon</xx1:Alias>
  1045. <xx1:Alias>Johnny</xx1:Alias>
  1046. <xx1:Alias>Johnnie</xx1:Alias>
  1047. </Name>
  1048. <Name>
  1049. <First>Jennifer</First>
  1050. <xx1:Alias>Jen</xx1:Alias>
  1051. <xx1:Alias>Jenny</xx1:Alias>
  1052. <xx1:Alias>Jenna</xx1:Alias>
  1053. </Name>
  1054. </Relatives>
  1055. <Friends>
  1056. <Name>
  1057. <First>Joe</First>
  1058. <xx1:Alias>Moe</xx1:Alias>
  1059. <xx1:Alias>Poe</xx1:Alias>
  1060. <xx1:Alias>Doe</xx1:Alias>
  1061. </Name>
  1062. <Name>
  1063. <First>Jane</First>
  1064. <xx1:Alias>Jan</xx1:Alias>
  1065. <xx1:Alias>Janie</xx1:Alias>
  1066. <xx1:Alias>Janet</xx1:Alias>
  1067. </Name>
  1068. </Friends>
  1069. </extra>
  1070. </root>)!!";
  1071. constexpr const char *configNada = R"!!(<config strictParams="true">
  1072. <Transform>
  1073. <Param name='testcase' value="for each nada target"/>
  1074. <Param name='section' select="'Friends'"/>
  1075. <Param name='garbage' select="'/nada'"/>
  1076. <Param name='ForBuildListPath' select='extra/Nada/Name'/>
  1077. <Param name='ForIdPath' select='extra/Friends/Name/First/Nada'/>
  1078. </Transform>
  1079. </config>)!!";
  1080. runTest("for each nada target", forEachScript, input, configNada, resultNada, 0);
  1081. }
  1082. void testEsdlTransformVarScope()
  1083. {
  1084. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1085. <root>
  1086. <extra>
  1087. <Friends>
  1088. <Name>
  1089. <First>Joe</First>
  1090. <Alias>Moe</Alias>
  1091. <Alias>Poe</Alias>
  1092. <Alias>Doe</Alias>
  1093. </Name>
  1094. <Name>
  1095. <First>Jane</First>
  1096. <Alias>Jan</Alias>
  1097. <Alias>Janie</Alias>
  1098. <Alias>Janet</Alias>
  1099. </Name>
  1100. </Friends>
  1101. </extra>
  1102. </root>
  1103. )!!";
  1104. static constexpr const char * script = R"!!(<CustomRequestTransform xmlns="urn:hpcc:esdl:script" target="extra">
  1105. <variable name="local" select="'root|'"/>
  1106. <variable name="halfway" select="'root|'"/>
  1107. <variable name="global" select="'root|'"/>
  1108. <append-to-value target="trace-local" select="$local"/>
  1109. <append-to-value target="trace-halfway" select="$halfway"/>
  1110. <append-to-value target="trace-global" select="$global"/>
  1111. <if test="true()">
  1112. <variable name="local" select="'if|'"/>
  1113. <append-to-value target="trace-local" select="$local"/>
  1114. <append-to-value target="trace-halfway" select="$halfway"/>
  1115. <append-to-value target="trace-global" select="$global"/>
  1116. </if>
  1117. <for-each select="extra/Friends/Name">
  1118. <variable name="local" select="'for1|'"/>
  1119. <variable name="q" select="str:decode-uri('%27')"/>
  1120. <variable name="path" select="concat('Friends/Name[First=', $q, First, $q, ']/Aliases')"/>
  1121. <append-to-value target="trace-local" select="$local"/>
  1122. <append-to-value target="trace-halfway" select="$halfway"/>
  1123. <append-to-value target="trace-global" select="$global"/>
  1124. <for-each select="Alias">
  1125. <variable name="halfway" select="'for2|'"/>
  1126. <variable name="local" select="'for2|'"/>
  1127. <append-to-value target="trace-local" select="$local"/>
  1128. <append-to-value target="trace-halfway" select="$halfway"/>
  1129. <append-to-value target="trace-global" select="$global"/>
  1130. <choose>
  1131. <when test="position()=1">
  1132. <variable name="local" select="'when|'"/>
  1133. <append-to-value xpath_target="$path" select="."/>
  1134. <append-to-value target="trace-local" select="$local"/>
  1135. <append-to-value target="trace-halfway" select="$halfway"/>
  1136. <append-to-value target="trace-global" select="$global"/>
  1137. </when>
  1138. <otherwise>
  1139. <variable name="local" select="'otherwise|'"/>
  1140. <append-to-value xpath_target="$path" select="','"/>
  1141. <append-to-value xpath_target="$path" select="."/>
  1142. <append-to-value target="trace-local" select="$local"/>
  1143. <append-to-value target="trace-halfway" select="$halfway"/>
  1144. <append-to-value target="trace-global" select="$global"/>
  1145. </otherwise>
  1146. </choose>
  1147. </for-each>
  1148. </for-each>
  1149. </CustomRequestTransform>
  1150. )!!";
  1151. constexpr const char * result = R"!!(<root>
  1152. <extra>
  1153. <trace-global>root|root|root|root|root|root|root|root|root|root|root|root|root|root|root|root|</trace-global>
  1154. <Friends>
  1155. <Name>
  1156. <Alias>Moe</Alias>
  1157. <Alias>Poe</Alias>
  1158. <Alias>Doe</Alias>
  1159. <Aliases>Moe,Poe,Doe</Aliases>
  1160. <First>Joe</First>
  1161. </Name>
  1162. <Name>
  1163. <Alias>Jan</Alias>
  1164. <Alias>Janie</Alias>
  1165. <Alias>Janet</Alias>
  1166. <Aliases>Jan,Janie,Janet</Aliases>
  1167. <First>Jane</First>
  1168. </Name>
  1169. </Friends>
  1170. <trace-halfway>for2|for2|for2|for2|for2|for2|root|for2|for2|for2|for2|for2|for2|root|root|root|</trace-halfway>
  1171. <trace-local>for2|when|for2|otherwise|for2|otherwise|for1|for2|when|for2|otherwise|for2|otherwise|for1|if|root|</trace-local>
  1172. </extra>
  1173. </root>)!!";
  1174. constexpr const char *config = R"!!(<config strictParams="true">
  1175. <Transform>
  1176. <Param name='testcase' value="variable scope"/>
  1177. </Transform>
  1178. </config>)!!";
  1179. runTest("variable scope", script, input, config, result, 0);
  1180. }
  1181. void testEsdlTransformLegacy()
  1182. {
  1183. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1184. <root>
  1185. <Person>
  1186. <Name>
  1187. <First>Joe</First>
  1188. </Name>
  1189. </Person>
  1190. </root>
  1191. )!!";
  1192. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1193. <es:SetValue target="ID" select="Person/Name/First"/>
  1194. <es:AppendValue target="Append" select="Person/Name/First"/>
  1195. <es:AppendValue target="Append" value="'++'"/>
  1196. </es:CustomRequestTransform>
  1197. )!!";
  1198. constexpr const char *config = R"!!(<config><Transform><Param name='testcase' value="legacy"/></Transform></config>)!!";
  1199. constexpr const char * result = R"!!(<root>
  1200. <Person>
  1201. <Append>Joe++</Append>
  1202. <Name>
  1203. <First>Joe</First>
  1204. </Name>
  1205. <ID>Joe</ID>
  1206. </Person>
  1207. </root>)!!";
  1208. runTest("legacy", script, input, config, result, 0);
  1209. }
  1210. void testEsdlTransformIgnoreScriptErrors()
  1211. {
  1212. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1213. <root>
  1214. <Person>
  1215. <Name>
  1216. <First>Joe</First>
  1217. </Name>
  1218. </Person>
  1219. </root>
  1220. )!!";
  1221. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1222. <es:SetValue optional='true'/>
  1223. <es:AppendValue select="Person/Name/First" optional='true'/>
  1224. <es:AppendValue target="Append" optional='true'/>
  1225. </es:CustomRequestTransform>
  1226. )!!";
  1227. constexpr const char *config = R"!!(<config><Transform><Param name='testcase' value="ignore script errors"/></Transform></config>)!!";
  1228. constexpr const char * result = R"!!(<root>
  1229. <Person>
  1230. <Name>
  1231. <First>Joe</First>
  1232. </Name>
  1233. </Person>
  1234. </root>)!!";
  1235. runTest("ignore script errors", script, input, config, result, 0);
  1236. }
  1237. void testEsdlTransformTargetXpathErrors()
  1238. {
  1239. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1240. <root>
  1241. <Person>
  1242. <Name>
  1243. <First>Joe</First>
  1244. </Name>
  1245. </Person>
  1246. </root>
  1247. )!!";
  1248. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1249. <es:SetValue xpath_target="concat('ID', '##')" select="/root/Person/Name/First"/>
  1250. <es:AppendValue target="Append" select="Person/Name/First"/>
  1251. <es:AppendValue target="Append" value="'++'"/>
  1252. </es:CustomRequestTransform>
  1253. )!!";
  1254. constexpr const char *config = R"!!(<config><Transform><Param name='testcase' value="target xpath errors"/></Transform></config>)!!";
  1255. runTest("target xpath errors", script, input, config, nullptr, 5682); //createPropBranch: cannot create path : ID##
  1256. static constexpr const char * script2 = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1257. <es:SetValue target="ID##" select="/root/Person/Name/First"/>
  1258. <es:AppendValue target="Append" select="Person/Name/First"/>
  1259. <es:AppendValue target="Append" value="'++'"/>
  1260. </es:CustomRequestTransform>
  1261. )!!";
  1262. runTest("target xpath errors", script2, input, config, nullptr, 5682); //createPropBranch: cannot create path : ID##
  1263. }
  1264. void testEsdlTransformFailLevel1A()
  1265. {
  1266. constexpr const char *config = R"!!(<config>
  1267. <Transform>
  1268. <Param name='testcase' value="fail Level1A"/>
  1269. <Param name='FailLevel1A' select='true()'/>
  1270. <Param name='FailLevel1B' select='true()'/>
  1271. <Param name='AssertLevel1C' select='true()'/>
  1272. <Param name='FailLevel2A' select='true()'/>
  1273. <Param name='FailLevel2B' select='true()'/>
  1274. <Param name='AssertLevel2C' select='true()'/>
  1275. </Transform>
  1276. </config>)!!";
  1277. runTest("fail Leve1A", esdlScript, soapRequest, config, nullptr, 11);
  1278. }
  1279. void testEsdlTransformFailLevel1B()
  1280. {
  1281. constexpr const char *config = R"!!(<config>
  1282. <Transform>
  1283. <Param name='testcase' value="fail Level1B"/>
  1284. <Param name='FailLevel1A' select='false()'/>
  1285. <Param name='FailLevel1B' select='true()'/>
  1286. <Param name='AssertLevel1C' select='true()'/>
  1287. <Param name='FailLevel2A' select='true()'/>
  1288. <Param name='FailLevel2B' select='true()'/>
  1289. <Param name='AssertLevel2C' select='true()'/>
  1290. </Transform>
  1291. </config>)!!";
  1292. runTest("fail Level1B", esdlScript, soapRequest, config, nullptr, 12);
  1293. }
  1294. void testEsdlTransformFailLevel1C()
  1295. {
  1296. constexpr const char *config = R"!!(<config>
  1297. <Transform>
  1298. <Param name='testcase' value="fail Level1C"/>
  1299. <Param name='FailLevel1A' select='false()'/>
  1300. <Param name='FailLevel1B' select='false()'/>
  1301. <Param name='AssertLevel1C' select='true()'/>
  1302. <Param name='FailLevel2A' select='true()'/>
  1303. <Param name='FailLevel2B' select='true()'/>
  1304. <Param name='AssertLevel2C' select='true()'/>
  1305. </Transform>
  1306. </config>)!!";
  1307. runTest("fail Level1C", esdlScript, soapRequest, config, nullptr, 13);
  1308. }
  1309. void testEsdlTransformFailLevel2A()
  1310. {
  1311. constexpr const char *config = R"!!(<config>
  1312. <Transform>
  1313. <Param name='testcase' value="fail Level2A"/>
  1314. <Param name='FailLevel1A' select='false()'/>
  1315. <Param name='FailLevel1B' select='false()'/>
  1316. <Param name='AssertLevel1C' select='false()'/>
  1317. <Param name='FailLevel2A' select='true()'/>
  1318. <Param name='FailLevel2B' select='true()'/>
  1319. <Param name='AssertLevel2C' select='true()'/>
  1320. </Transform>
  1321. </config>)!!";
  1322. runTest("fail Level2A", esdlScript, soapRequest, config, nullptr, 21);
  1323. }
  1324. void testEsdlTransformFailLevel2B()
  1325. {
  1326. constexpr const char *config = R"!!(<config>
  1327. <Transform>
  1328. <Param name='testcase' value="fail Level2B"/>
  1329. <Param name='FailLevel1A' select='false()'/>
  1330. <Param name='FailLevel1B' select='false()'/>
  1331. <Param name='AssertLevel1C' select='false()'/>
  1332. <Param name='FailLevel2A' select='false()'/>
  1333. <Param name='FailLevel2B' select='true()'/>
  1334. <Param name='AssertLevel2C' select='true()'/>
  1335. </Transform>
  1336. </config>)!!";
  1337. runTest("fail Level2B", esdlScript, soapRequest, config, nullptr, 22);
  1338. }
  1339. void testEsdlTransformFailLevel2C()
  1340. {
  1341. constexpr const char *config = R"!!(<config>
  1342. <Transform>
  1343. <Param name='testcase' value="fail Level2C"/>
  1344. <Param name='FailLevel1A' select='false()'/>
  1345. <Param name='FailLevel1B' select='false()'/>
  1346. <Param name='AssertLevel1C' select='false()'/>
  1347. <Param name='FailLevel2A' select='false()'/>
  1348. <Param name='FailLevel2B' select='false()'/>
  1349. <Param name='AssertLevel2C' select='true()'/>
  1350. </Transform>
  1351. </config>)!!";
  1352. runTest("fail Level2C", esdlScript, soapRequest, config, nullptr, 23);
  1353. }
  1354. void testScriptContext()
  1355. {
  1356. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1357. <root>
  1358. <Person>
  1359. <FullName>
  1360. <First>Joe</First>
  1361. <ID>GI101</ID>
  1362. <ID>GI102</ID>
  1363. </FullName>
  1364. </Person>
  1365. </root>
  1366. )!!";
  1367. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1368. <es:param name="testpass"/>
  1369. <es:if test="es:storedValueExists('myvalue')">
  1370. <es:set-value xpath_target="concat('check-value1-pass-', $testpass)" select="concat('already set as of pass-', $testpass)"/>
  1371. <es:set-value target="myvalue" select="es:getStoredStringValue('myvalue')"/>
  1372. <es:remove-node target="Name/ID[1]"/> //removing first one changes the index count so each is 1
  1373. <es:remove-node target="Name/ID[1]"/>
  1374. </es:if>
  1375. <es:if test="es:storedValueExists('myvalue2')">
  1376. <es:set-value xpath_target="concat('check-value2-pass-', $testpass)" select="concat('already set in pass-', $testpass)"/>
  1377. <es:set-value target="myvalue2" select="es:getStoredStringValue('myvalue2')"/>
  1378. </es:if>
  1379. <es:if test="es:logOptionExists('option1')">
  1380. <es:set-value xpath_target="concat('check-logging-option1-pass-', $testpass)" select="concat('already set in pass-', $testpass)"/>
  1381. <es:set-value target="logging-option1" select="es:getLogOption('option1')"/>
  1382. <es:set-value target="logging-option2" select="es:getLogOption('option2')"/>
  1383. <es:set-value target="profile" select="es:getLogProfile()"/>
  1384. </es:if>
  1385. <es:if test="not(es:storedValueExists('myvalue'))">
  1386. <es:set-value xpath_target="concat('check-set-pass-', $testpass)" select="concat('not already set in pass-', $testpass)"/>
  1387. <es:store-value xpath_name="'myvalue2'" select="'another stored value'"/>
  1388. <es:store-value name="myvalue" select="'this is a stored value'"/>
  1389. <es:set-log-option name="option1" select="'this is a logging option value'"/>
  1390. <es:set-log-option xpath_name="'option2'" select="'this is an xpath named logging option value'"/>
  1391. <es:set-log-profile select="'myprofile'"/>
  1392. <es:rename-node target="FullName" new_name="Name"/>
  1393. </es:if>
  1394. </es:CustomRequestTransform>
  1395. )!!";
  1396. constexpr const char *config1 = R"!!(<config>
  1397. <Transform>
  1398. <Param name='testcase' value="script context 1"/>
  1399. <Param name='testpass' value="1"/>
  1400. </Transform>
  1401. </config>)!!";
  1402. constexpr const char *config2 = R"!!(<config>
  1403. <Transform>
  1404. <Param name='testcase' value="script context 2"/>
  1405. <Param name='testpass' value="2"/>
  1406. </Transform>
  1407. </config>)!!";
  1408. try
  1409. {
  1410. Owned<IEspContext> ctx = createEspContext(nullptr);
  1411. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, input, config1);
  1412. runTransform(scriptContext, script, ESDLScriptCtxSection_ESDLRequest, "FirstPass", "script context 1", 0);
  1413. scriptContext->setContent(ESDLScriptCtxSection_BindingConfig, config2);
  1414. runTransform(scriptContext, script, "FirstPass", "SecondPass", "script context 2", 0);
  1415. constexpr const char * result = R"!!(<root>
  1416. <Person>
  1417. <Name>
  1418. <First>Joe</First>
  1419. </Name>
  1420. <myvalue>this is a stored value</myvalue>
  1421. <myvalue2>another stored value</myvalue2>
  1422. <logging-option1>this is a logging option value</logging-option1>
  1423. <check-set-pass-1>not already set in pass-1</check-set-pass-1>
  1424. <check-value2-pass-2>already set in pass-2</check-value2-pass-2>
  1425. <logging-option2>this is an xpath named logging option value</logging-option2>
  1426. <profile>myprofile</profile>
  1427. <check-logging-option1-pass-2>already set in pass-2</check-logging-option1-pass-2>
  1428. <check-value1-pass-2>already set as of pass-2</check-value1-pass-2>
  1429. </Person>
  1430. </root>)!!";
  1431. StringBuffer output;
  1432. scriptContext->toXML(output, "SecondPass");
  1433. if (result && !areEquivalentTestXMLStrings(result, output.str()))
  1434. {
  1435. fputs(output.str(), stdout);
  1436. fflush(stdout);
  1437. throw MakeStringException(100, "Test failed(%s)", "script context");
  1438. }
  1439. }
  1440. catch (IException *E)
  1441. {
  1442. StringBuffer m;
  1443. fprintf(stdout, "\nTest(%s) Exception %d - %s\n", "script context", E->errorCode(), E->errorMessage(m).str());
  1444. E->Release();
  1445. CPPUNIT_ASSERT(false);
  1446. }
  1447. }
  1448. void testTargetElement()
  1449. {
  1450. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1451. <root>
  1452. <Person>
  1453. <FullName>
  1454. <First>Joe</First>
  1455. <ID>GI101</ID>
  1456. <ID>GI102</ID>
  1457. </FullName>
  1458. <Friends>Jane,John,Jaap,Jessica</Friends>
  1459. </Person>
  1460. </root>
  1461. )!!";
  1462. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1463. <es:variable name='value' select="'abc'"/>
  1464. <es:if-source xpath="NotThere">
  1465. <es:element name="NeverHere">
  1466. <es:copy-of select="."/>
  1467. </es:element>
  1468. </es:if-source>
  1469. <es:if-source xpath="Person">
  1470. <es:set-value target="@found" select="true()"/>
  1471. </es:if-source>
  1472. <es:source xpath="Person">
  1473. <es:ensure-target xpath='How/Did/We/Get'>
  1474. <es:element name='Here'>
  1475. <es:variable name="tkns" select="es:tokenize('aaa,bbb;ccc+yyy', ',;+')"/>
  1476. <es:variable name="friends" select="es:tokenize(Friends, ',')"/>
  1477. <es:set-value target="@whoknows" select="$value"/>
  1478. <es:set-value target="IDontKnow" select="$value"/>
  1479. <es:element name="CopyTokens">
  1480. <es:copy-of select="$tkns"/>
  1481. </es:element>
  1482. <es:element name="CopyFriends">
  1483. <es:copy-of select="$friends"/>
  1484. </es:element>
  1485. <es:element name="CopyFields">
  1486. <es:for-each select="FullName/*">
  1487. <es:element name="CopyField">
  1488. <es:copy-of select="."/>
  1489. </es:element>
  1490. </es:for-each>
  1491. </es:element>
  1492. <es:element name="CopyFullName">
  1493. <es:copy-of select="FullName" new_name='FullerName'/>
  1494. <es:set-value target="FullerName/@valid" select="true()"/>
  1495. </es:element>
  1496. </es:element>
  1497. </es:ensure-target>
  1498. </es:source>
  1499. <es:if-target xpath='PartName'>
  1500. <es:set-value target="NotSet" select="$value"/>
  1501. </es:if-target>
  1502. <es:if-target xpath='FullName'>
  1503. <es:set-value target="IsSet" select="$value"/>
  1504. </es:if-target>
  1505. <es:target xpath='FullName'>
  1506. <es:set-value target="DidntFail" select="$value"/>
  1507. </es:target>
  1508. </es:CustomRequestTransform>
  1509. )!!";
  1510. constexpr const char *config1 = R"!!(<config>
  1511. <Transform>
  1512. <Param name='testcase' value="new features"/>
  1513. </Transform>
  1514. </config>)!!";
  1515. constexpr const char * result = R"!!(<root>
  1516. <Person found="true">
  1517. <FullName>
  1518. <First>Joe</First>
  1519. <ID>GI101</ID>
  1520. <ID>GI102</ID>
  1521. <IsSet>abc</IsSet>
  1522. <DidntFail>abc</DidntFail>
  1523. </FullName>
  1524. <Friends>Jane,John,Jaap,Jessica</Friends>
  1525. <How>
  1526. <Did>
  1527. <We>
  1528. <Get>
  1529. <Here whoknows="abc">
  1530. <IDontKnow>abc</IDontKnow>
  1531. <CopyTokens>
  1532. <token>aaa</token>
  1533. <token>bbb</token>
  1534. <token>ccc</token>
  1535. <token>yyy</token>
  1536. </CopyTokens>
  1537. <CopyFriends>
  1538. <token>Jane</token>
  1539. <token>John</token>
  1540. <token>Jaap</token>
  1541. <token>Jessica</token>
  1542. </CopyFriends>
  1543. <CopyFields>
  1544. <CopyField>
  1545. <First>Joe</First>
  1546. </CopyField>
  1547. <CopyField>
  1548. <ID>GI101</ID>
  1549. </CopyField>
  1550. <CopyField>
  1551. <ID>GI102</ID>
  1552. </CopyField>
  1553. </CopyFields>
  1554. <CopyFullName>
  1555. <FullerName valid="true">
  1556. <First>Joe</First>
  1557. <ID>GI101</ID>
  1558. <ID>GI102</ID>
  1559. </FullerName>
  1560. </CopyFullName>
  1561. </Here>
  1562. </Get>
  1563. </We>
  1564. </Did>
  1565. </How>
  1566. </Person>
  1567. </root>)!!";
  1568. try {
  1569. Owned<IEspContext> ctx = createEspContext(nullptr);
  1570. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, input, config1);
  1571. runTransform(scriptContext, script, ESDLScriptCtxSection_ESDLRequest, "FirstPass", "target element 1", 0);
  1572. StringBuffer output;
  1573. scriptContext->toXML(output, "FirstPass");
  1574. if (result && !areEquivalentTestXMLStrings(result, output.str()))
  1575. {
  1576. fputs(output.str(), stdout);
  1577. fflush(stdout);
  1578. throw MakeStringException(100, "Test failed(%s)", "target element");
  1579. }
  1580. }
  1581. catch (IException *E)
  1582. {
  1583. StringBuffer m;
  1584. fprintf(stdout, "\nTest(%s) Exception %d - %s\n", "target element", E->errorCode(), E->errorMessage(m).str());
  1585. E->Release();
  1586. CPPUNIT_ASSERT(false);
  1587. }
  1588. }
  1589. void testHTTPPostXml()
  1590. {
  1591. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1592. <root>
  1593. <Person>
  1594. <FullName>
  1595. <First>Joe</First>
  1596. <ID>GI101</ID>
  1597. <ID>GI102</ID>
  1598. </FullName>
  1599. </Person>
  1600. </root>
  1601. )!!";
  1602. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1603. <es:variable name='value' select="'abc'"/>
  1604. <es:http-post-xml url="'http://127.0.0.1:9876'" section="logging" name="roxiestuff">
  1605. <es:content>
  1606. <es:element name="Envelope">
  1607. <es:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/" current="true" />
  1608. <es:element name="Body">
  1609. <es:element name="roxieechopersoninfoRequest">
  1610. <es:namespace uri="urn:hpccsystems:ecl:roxieechopersoninfo" current="true" />
  1611. <es:element name="roxieechopersoninforequest">
  1612. <es:element name="Row">
  1613. <es:element name="Name">
  1614. <es:set-value target="First" value="'aaa'"/>
  1615. <es:set-value target="Last" value="'bbb'"/>
  1616. <es:element name="Aliases">
  1617. <es:set-value target="Alias" value="'ccc'"/>
  1618. <es:set-value target="Alias" value="'ddd'"/>
  1619. <es:add-value target="Alias" value="'eee'"/>
  1620. </es:element>
  1621. </es:element>
  1622. </es:element>
  1623. </es:element>
  1624. </es:element>
  1625. </es:element>
  1626. </es:element>
  1627. </es:content>
  1628. </es:http-post-xml>
  1629. <es:element name="HttpPostStuff">
  1630. <es:copy-of select="$roxiestuff"/>
  1631. </es:element>
  1632. </es:CustomRequestTransform>
  1633. )!!";
  1634. constexpr const char *config1 = R"!!(<config>
  1635. <Transform>
  1636. <Param name='testcase' value="new features"/>
  1637. </Transform>
  1638. </config>)!!";
  1639. constexpr const char * result = R"!!(<root>
  1640. <Person>
  1641. <FullName>
  1642. <First>Joe</First>
  1643. <ID>GI101</ID>
  1644. <ID>GI102</ID>
  1645. </FullName>
  1646. <HttpPostStuff>
  1647. <roxiestuff>
  1648. <request url="http://127.0.0.1:9876">
  1649. <content>
  1650. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  1651. <soap:Body>
  1652. <roxieechopersoninfoRequest xmlns="urn:hpccsystems:ecl:roxieechopersoninfo">
  1653. <roxieechopersoninforequest>
  1654. <Row>
  1655. <Name>
  1656. <First>aaa</First>
  1657. <Last>bbb</Last>
  1658. <Aliases>
  1659. <Alias>ccc</Alias>
  1660. <Alias>ddd</Alias>
  1661. </Aliases>
  1662. </Name>
  1663. </Row>
  1664. </roxieechopersoninforequest>
  1665. </roxieechopersoninfoRequest>
  1666. </soap:Body>
  1667. </soap:Envelope>
  1668. </content>
  1669. </request>
  1670. <response status="200 OK" error-code="0" content-type="text/xml">
  1671. <content>
  1672. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  1673. <soap:Body>
  1674. <roxieechopersoninfoResponse xmlns="urn:hpccsystems:ecl:roxieechopersoninfo" sequence="0">
  1675. <Results>
  1676. <Result>
  1677. <Dataset xmlns="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse" name="RoxieEchoPersonInfoResponse">
  1678. <Row>
  1679. <Name>
  1680. <First>aaa</First>
  1681. <Last>bbb</Last>
  1682. <Aliases>
  1683. <Alias>ddd</Alias>
  1684. <Alias>eee</Alias>
  1685. </Aliases>
  1686. </Name>
  1687. <Addresses/>
  1688. </Row>
  1689. </Dataset>
  1690. </Result>
  1691. </Results>
  1692. </roxieechopersoninfoResponse>
  1693. </soap:Body>
  1694. </soap:Envelope>
  1695. </content>
  1696. </response>
  1697. </roxiestuff>
  1698. </HttpPostStuff>
  1699. </Person>
  1700. </root>)!!";
  1701. try {
  1702. Owned<IEspContext> ctx = createEspContext(nullptr);
  1703. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, input, config1);
  1704. runTransform(scriptContext, script, ESDLScriptCtxSection_ESDLRequest, "MyResult", "http post xml", 0);
  1705. StringBuffer output;
  1706. scriptContext->toXML(output, "MyResult");
  1707. if (result && !areEquivalentTestXMLStrings(result, output.str()))
  1708. {
  1709. fputs(output.str(), stdout);
  1710. fflush(stdout);
  1711. throw MakeStringException(100, "Test failed(%s)", "http post xml");
  1712. }
  1713. }
  1714. catch (IException *E)
  1715. {
  1716. StringBuffer m;
  1717. fprintf(stdout, "\nTest(%s) Exception %d - %s\n", "http post xml", E->errorCode(), E->errorMessage(m).str());
  1718. E->Release();
  1719. CPPUNIT_ASSERT(false);
  1720. }
  1721. }
  1722. void testMysql()
  1723. {
  1724. constexpr const char *config1 = R"!!(<config>
  1725. <Transform>
  1726. <Param name='testcase' value="new features"/>
  1727. </Transform>
  1728. </config>)!!";
  1729. static constexpr const char * data = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1730. <root>
  1731. <insert>
  1732. <common_value>178</common_value>
  1733. <common_r8>1.2</common_r8>
  1734. <Row>
  1735. <name>selected1</name>
  1736. <bval>65</bval>
  1737. <boolval>1</boolval>
  1738. <r4>3.4</r4>
  1739. <d>aa55aa55</d>
  1740. <ddd>1234567.89</ddd>
  1741. <u1>Straße1</u1>
  1742. <u2>ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ</u2>
  1743. <dt>2019-02-01 12:59:59</dt>
  1744. </Row>
  1745. <Row>
  1746. <name>selected2</name>
  1747. <bval>65</bval>
  1748. <boolval>1</boolval>
  1749. <r4>4.5</r4>
  1750. <d>bb66bb66</d>
  1751. <ddd>1234567.89</ddd>
  1752. <u1>Straße3</u1>
  1753. <u2>Straße4</u2>
  1754. <dt>2019-02-01 13:59:59</dt>
  1755. </Row>
  1756. <Row>
  1757. <name>selected3</name>
  1758. <bval>65</bval>
  1759. <boolval>1</boolval>
  1760. <r4>5.6</r4>
  1761. <d>cc77cc77</d>
  1762. <ddd>1234567.89</ddd>
  1763. <u1>Straße5</u1>
  1764. <u2>色は匂へど 散りぬるを</u2>
  1765. <dt>2019-02-01 14:59:59</dt>
  1766. </Row>
  1767. </insert>
  1768. <cities>
  1769. <name>aeiou</name>
  1770. <name>aeou</name>
  1771. <name>aoui</name>
  1772. <name>ei</name>
  1773. <name>aaa</name>
  1774. <name>bbb</name>
  1775. </cities>
  1776. <read>
  1777. <name>selected1</name>
  1778. <name>selected3</name>
  1779. </read>
  1780. </root>
  1781. )!!";
  1782. static constexpr const char * input = R"!!(<?xml version="1.0" encoding="UTF-8"?>
  1783. <root>
  1784. <Person>
  1785. <FullName>
  1786. <First>Joe</First>
  1787. </FullName>
  1788. </Person>
  1789. </root>
  1790. )!!";
  1791. static constexpr const char * script = R"!!(<es:CustomRequestTransform xmlns:es="urn:hpcc:esdl:script" target="Person">
  1792. <es:variable name="secret" select="'mydb'"/>
  1793. <es:variable name="database" select="'classicmodels'"/>
  1794. <es:variable name="section" select="'sql'"/>
  1795. <es:mysql secret="$secret" database="$database" section="$section" name="drop">
  1796. <es:sql>DROP TABLE IF EXISTS tbl1;</es:sql>
  1797. </es:mysql>
  1798. <es:mysql secret="$secret" database="$database" section="$section" name="create">
  1799. <es:sql>CREATE TABLE tbl1 ( name VARCHAR(20), bval BIT(15), value INT, boolval TINYINT, r8 DOUBLE, r4 FLOAT, d BLOB, ddd DECIMAL(10,2), u1 VARCHAR(10), u2 VARCHAR(10), dt DATETIME );</es:sql>
  1800. </es:mysql>
  1801. <es:mysql select="getDataSection('whatever')/this/insert/Row" secret="$secret" database="$database" section="$section" name="insert_each_row" resultset-tag="'inserted'">
  1802. <es:bind name="name" value="name"/>
  1803. <es:bind name="bval" value="bval" type="BIT(15)"/>
  1804. <es:bind name="value" value="../common_value"/>
  1805. <es:bind name="boolval" value="boolval"/>
  1806. <es:bind name="r8" value="../common_r8"/>
  1807. <es:bind name="r4" value="r4"/>
  1808. <es:bind name="d" value="d"/>
  1809. <es:bind name="ddd" value="ddd"/>
  1810. <es:bind name="u1" value="u1"/>
  1811. <es:bind name="u2" value="u2"/>
  1812. <es:bind name="dt" value="dt"/>
  1813. <es:sql>INSERT INTO tbl1 values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);</es:sql>
  1814. </es:mysql>
  1815. <es:mysql secret="$secret" database="$database" section="$section" name="drop">
  1816. <es:sql>DROP TABLE IF EXISTS tblcities;</es:sql>
  1817. </es:mysql>
  1818. <es:mysql secret="$secret" database="$database" section="$section" name="createcites">
  1819. <es:sql>CREATE TABLE tblcities ( city VARCHAR(20) );</es:sql>
  1820. </es:mysql>
  1821. <es:mysql select="getDataSection('whatever')/this/cities/name" secret="$secret" database="$database" section="$section" name="insert_each_row" resultset-tag="'inserted'">
  1822. <es:bind name="city" value="."/>
  1823. <es:sql>INSERT INTO tblcities values (?);</es:sql>
  1824. </es:mysql>
  1825. <es:mysql select="getDataSection('whatever')/this/read/name" secret="$secret" database="$database" section="$section" name="select_each_name" resultset-tag="'selected'">
  1826. <es:bind name="name" value="."/>
  1827. <es:sql>SELECT * FROM tbl1 where name = ?;</es:sql>
  1828. </es:mysql>
  1829. <es:mysql secret="$secret" database="$database" section="$section" name="mysql_session_info" MYSQL_SET_CHARSET_NAME="'latin1'">
  1830. <es:sql>
  1831. SELECT * FROM performance_schema.session_variables
  1832. WHERE VARIABLE_NAME IN (
  1833. 'character_set_client', 'character_set_connection',
  1834. 'character_set_results', 'collation_connection'
  1835. ) ORDER BY VARIABLE_NAME;
  1836. </es:sql>
  1837. </es:mysql>
  1838. <es:mysql secret="$secret" database="$database" section="$section" name="select_all" resultset-tag="'onecall'">
  1839. <es:sql>SELECT * FROM tbl1;</es:sql>
  1840. </es:mysql>
  1841. <es:for-each select="$select_all/onecall/Row">
  1842. <es:element name="r">
  1843. <es:copy-of select="*"/>
  1844. </es:element>
  1845. </es:for-each>
  1846. <es:mysql secret="$secret" database="$database" section="$section" name="mysqlresult">
  1847. <es:sql>SELECT * FROM tblcities;</es:sql>
  1848. </es:mysql>
  1849. <es:variable name="i" select="$mysqlresult/Row/city[contains(.,'i')]" />
  1850. <es:variable name="e" select="$mysqlresult/Row/city[contains(.,'e')]" />
  1851. <es:ensure-target xpath="iii">
  1852. <es:copy-of select="$i" />
  1853. </es:ensure-target>
  1854. <es:ensure-target xpath="eee">
  1855. <es:copy-of select="$e" />
  1856. </es:ensure-target>
  1857. <es:ensure-target xpath="cities">
  1858. <es:for-each select="set:intersection($i, $e)">
  1859. <es:copy-of select="." />
  1860. </es:for-each>
  1861. </es:ensure-target>
  1862. </es:CustomRequestTransform>
  1863. )!!";
  1864. Owned<IEspContext> ctx = createEspContext(nullptr);
  1865. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, input, config1);
  1866. scriptContext->appendContent("whatever", "this", data);
  1867. try
  1868. {
  1869. runTransform(scriptContext, script, ESDLScriptCtxSection_ESDLRequest, "MyResult", "http post xml", 0);
  1870. }
  1871. catch (IException *E)
  1872. {
  1873. StringBuffer m;
  1874. fprintf(stdout, "\nTest(%s) Exception %d - %s\n", "mysql", E->errorCode(), E->errorMessage(m).str());
  1875. E->Release();
  1876. }
  1877. StringBuffer output;
  1878. scriptContext->toXML(output);
  1879. fputs(output.str(), stdout);
  1880. fflush(stdout);
  1881. }
  1882. void testScriptMap()
  1883. {
  1884. constexpr const char * serverScripts = R"!!(<Transforms xmlns:es='urn:hpcc:esdl:script'>
  1885. <es:BackendRequest>
  1886. <es:set-value target="Row/Name/First" value="'modified-request-at-service'" />
  1887. </es:BackendRequest>
  1888. <es:BackendRequest>
  1889. <es:set-value target="BRSRV2" value="'s2'" />
  1890. </es:BackendRequest>
  1891. <es:BackendRequest>
  1892. <es:set-value target="BRSRV3" value="'s3'" />
  1893. </es:BackendRequest>
  1894. <es:BackendResponse xmlns:resp="urn:hpccsystems:ecl:roxieechopersoninfo" xmlns:ds1="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse">
  1895. <es:target xpath="soap:Body">
  1896. <es:target xpath="resp:roxieechopersoninfoResponse">
  1897. <es:target xpath="resp:Results/resp:Result">
  1898. <es:target xpath="ds1:Dataset[@name='RoxieEchoPersonInfoResponse']">
  1899. <es:set-value target="ds1:Row/ds1:Name/ds1:Last" value="'modified-response-at-service'" />
  1900. </es:target>
  1901. </es:target>
  1902. </es:target>
  1903. </es:target>
  1904. </es:BackendResponse>
  1905. <es:BackendResponse>
  1906. <es:set-value target="BRESPSRV2" value="'s22'" />
  1907. </es:BackendResponse>
  1908. <es:BackendResponse>
  1909. <es:set-value target="BRESPSRV3" value="'s33'" />
  1910. </es:BackendResponse>
  1911. <es:PreLogging>
  1912. <es:set-value target="PLSRV1" value="'s111'" />
  1913. </es:PreLogging>
  1914. <es:PreLogging>
  1915. <es:set-value target="PLSRV2" value="'s222'" />
  1916. </es:PreLogging>
  1917. <es:PreLogging>
  1918. <es:set-value target="PLSRV3" value="'s333'" />
  1919. </es:PreLogging>
  1920. </Transforms>)!!";
  1921. constexpr const char * methodScripts = R"!!(<Transforms xmlns:es='urn:hpcc:esdl:script'>
  1922. <es:BackendRequest>
  1923. <es:append-to-value target="Row/Name/First" value="'-and-method'" />
  1924. </es:BackendRequest>
  1925. <es:BackendRequest>
  1926. <es:set-value target="BRMTH2" value="'m2'" />
  1927. </es:BackendRequest>
  1928. <es:BackendRequest>
  1929. <es:set-value target="BRMTH3" value="'m3'" />
  1930. </es:BackendRequest>
  1931. <es:BackendResponse xmlns:resp="urn:hpccsystems:ecl:roxieechopersoninfo" xmlns:ds1="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse">
  1932. <es:target xpath="soap:Body">
  1933. <es:target xpath="resp:roxieechopersoninfoResponse">
  1934. <es:target xpath="resp:Results/resp:Result">
  1935. <es:target xpath="ds1:Dataset[@name='RoxieEchoPersonInfoResponse']">
  1936. <es:append-to-value target="ds1:Row/ds1:Name/ds1:Last" value="'-and-method'" />
  1937. </es:target>
  1938. </es:target>
  1939. </es:target>
  1940. </es:target>
  1941. </es:BackendResponse>
  1942. <es:BackendResponse xmlns:resp="urn:hpccsystems:ecl:roxieechopersoninfo" xmlns:ds1="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse">
  1943. <es:http-post-xml url="'http://127.0.0.1:9876'" section="logdata/LogDataset" name="roxie_call_success">
  1944. <es:content>
  1945. <es:element name="Envelope">
  1946. <es:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/" current="true" />
  1947. <es:element name="Body">
  1948. <es:element name="roxieechopersoninfoRequest">
  1949. <es:namespace uri="urn:hpccsystems:ecl:roxieechopersoninfo" current="true" />
  1950. <es:element name="roxieechopersoninforequest">
  1951. <es:element name="Row">
  1952. <es:element name="Name">
  1953. <es:set-value target="First" value="'echoFirst'"/>
  1954. <es:set-value target="Last" value="'echoLast'"/>
  1955. <es:element name="Aliases">
  1956. <es:set-value target="Alias" value="'echoA1'"/>
  1957. <es:add-value target="Alias" value="'echoA2'"/>
  1958. </es:element>
  1959. </es:element>
  1960. </es:element>
  1961. </es:element>
  1962. </es:element>
  1963. </es:element>
  1964. </es:element>
  1965. </es:content>
  1966. </es:http-post-xml>
  1967. <es:target xpath="soap:Body">
  1968. <es:target xpath="resp:roxieechopersoninfoResponse">
  1969. <es:target xpath="resp:Results/resp:Result">
  1970. <es:target xpath="ds1:Dataset[@name='RoxieEchoPersonInfoResponse']">
  1971. <es:source xpath="$roxie_call_success/response/content">
  1972. <es:source xpath="soap:Envelope/soap:Body">
  1973. <es:source xpath="resp:roxieechopersoninfoResponse/resp:Results/resp:Result">
  1974. <es:source xpath="ds1:Dataset/ds1:Row">
  1975. <es:append-to-value target="ds1:Row/ds1:Name/ds1:Last" value="concat('-plus-echoed-alias-', ds1:Name/ds1:Aliases/ds1:Alias[2])" />
  1976. </es:source>
  1977. </es:source>
  1978. </es:source>
  1979. </es:source>
  1980. </es:target>
  1981. </es:target>
  1982. </es:target>
  1983. </es:target>
  1984. </es:BackendResponse>
  1985. <es:BackendResponse>
  1986. <es:set-value target="BRESPMTH3" value="'m33'" />
  1987. </es:BackendResponse>
  1988. <es:PreLogging>
  1989. <es:http-post-xml url="'http://127.0.0.1:9876'" section="logdata/LogDatasets" name="roxie_call_exception">
  1990. <es:content>
  1991. <es:element name="Envelope">
  1992. <es:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/" current="true" />
  1993. <es:element name="Body">
  1994. <es:element name="nonexistent_query">
  1995. <es:namespace uri="urn:hpccsystems:ecl:roxieechopersoninfo" current="true" />
  1996. <es:element name="nonexistent_queryrequest">
  1997. <es:element name="Row">
  1998. <es:element name="Name">
  1999. <es:set-value target="First" value="'aaa'"/>
  2000. <es:set-value target="Last" value="'bbb'"/>
  2001. <es:element name="Aliases">
  2002. <es:set-value target="Alias" value="'ccc'"/>
  2003. <es:set-value target="Alias" value="'ddd'"/>
  2004. </es:element>
  2005. </es:element>
  2006. </es:element>
  2007. </es:element>
  2008. </es:element>
  2009. </es:element>
  2010. </es:element>
  2011. </es:content>
  2012. </es:http-post-xml>
  2013. </es:PreLogging>
  2014. <es:PreLogging>
  2015. <es:set-value target="PLMTH2" value="'m222'" />
  2016. </es:PreLogging>
  2017. <es:PreLogging>
  2018. <es:set-value target="PLMTH3" value="'m333'" />
  2019. </es:PreLogging>
  2020. </Transforms>)!!";
  2021. constexpr const char * input = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  2022. <soap:Body>
  2023. <roxieechopersoninfoResponse xmlns="urn:hpccsystems:ecl:roxieechopersoninfo" sequence="0">
  2024. <Results>
  2025. <Result>
  2026. <Dataset xmlns="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse" name="RoxieEchoPersonInfoResponse">
  2027. <Row>
  2028. <Name>
  2029. <First>aaa</First>
  2030. <Last>bbbb</Last>
  2031. <Aliases>
  2032. <Alias>a</Alias>
  2033. <Alias>b</Alias>
  2034. <Alias>c</Alias>
  2035. </Aliases>
  2036. </Name>
  2037. <Addresses>
  2038. <Address>
  2039. <Line1>111</Line1>
  2040. <Line2>222</Line2>
  2041. <City>Boca Raton</City>
  2042. <State>FL</State>
  2043. <Zip>33487</Zip>
  2044. <type>ttt</type>
  2045. </Address>
  2046. </Addresses>
  2047. </Row>
  2048. </Dataset>
  2049. </Result>
  2050. </Results>
  2051. </roxieechopersoninfoResponse>
  2052. </soap:Body>
  2053. </soap:Envelope>)!!";
  2054. constexpr const char *config1 = R"!!(<config>
  2055. <Transform>
  2056. <Param name='testcase' value="transform map"/>
  2057. </Transform>
  2058. </config>)!!";
  2059. constexpr const char * result = R"!!(<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  2060. <soap:Body>
  2061. <roxieechopersoninfoResponse xmlns="urn:hpccsystems:ecl:roxieechopersoninfo" sequence="0">
  2062. <Results>
  2063. <Result>
  2064. <Dataset xmlns="urn:hpccsystems:ecl:roxieechopersoninfo:result:roxieechopersoninforesponse" name="RoxieEchoPersonInfoResponse">
  2065. <Row>
  2066. <Name>
  2067. <First>aaa</First>
  2068. <Last>modified-response-at-service-and-method-plus-echoed-alias-echoA2</Last>
  2069. <Aliases>
  2070. <Alias>a</Alias>
  2071. <Alias>b</Alias>
  2072. <Alias>c</Alias>
  2073. </Aliases>
  2074. </Name>
  2075. <Addresses>
  2076. <Address>
  2077. <Line1>111</Line1>
  2078. <Line2>222</Line2>
  2079. <City>Boca Raton</City>
  2080. <State>FL</State>
  2081. <Zip>33487</Zip>
  2082. <type>ttt</type>
  2083. </Address>
  2084. </Addresses>
  2085. </Row>
  2086. </Dataset>
  2087. </Result>
  2088. </Results>
  2089. </roxieechopersoninfoResponse>
  2090. </soap:Body>
  2091. <BRESPSRV2>s22</BRESPSRV2>
  2092. <BRESPSRV3>s33</BRESPSRV3>
  2093. <BRESPMTH3>m33</BRESPMTH3>
  2094. </soap:Envelope>)!!";
  2095. Owned<IEspContext> ctx = createEspContext(nullptr);
  2096. Owned<IEsdlScriptContext> scriptContext = createTestScriptContext(ctx, input, config1);
  2097. bool legacy = false;
  2098. Owned<IEsdlTransformMethodMap> map = createEsdlTransformMethodMap();
  2099. map->addMethodTransforms("", serverScripts, legacy);
  2100. map->addMethodTransforms("mymethod", methodScripts, legacy);
  2101. IEsdlTransformSet *serviceSet = map->queryMethodEntryPoint("", "BackendResponse");
  2102. IEsdlTransformSet *methodSet = map->queryMethodEntryPoint("mymethod", "BackendResponse");
  2103. scriptContext->setContent(ESDLScriptCtxSection_InitialResponse, input);
  2104. processServiceAndMethodTransforms(scriptContext, {serviceSet, methodSet}, ESDLScriptCtxSection_InitialResponse, "MyResult");
  2105. StringBuffer output;
  2106. scriptContext->toXML(output, "MyResult");
  2107. if (result && !areEquivalentTestXMLStrings(result, output.str()))
  2108. {
  2109. fputs(output.str(), stdout);
  2110. fflush(stdout);
  2111. throw MakeStringException(100, "Test failed(%s)", "transform map");
  2112. }
  2113. }
  2114. };
  2115. CPPUNIT_TEST_SUITE_REGISTRATION( ESDLTests );
  2116. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ESDLTests, "ESDL" );
  2117. #endif // _USE_CPPUNIT