]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
c12b3faef30c4b8a539c7d783b45b8c19a011f10
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.IntegrationTests.xmlreplay;\r
2 \r
3 import org.apache.commons.cli.*;\r
4 \r
5 import org.apache.commons.jexl2.JexlContext;\r
6 import org.apache.commons.jexl2.JexlEngine;\r
7 import org.apache.commons.jexl2.MapContext;\r
8 import org.dom4j.Document;\r
9 import org.dom4j.DocumentException;\r
10 import org.dom4j.Node;\r
11 import org.dom4j.io.SAXReader;\r
12 \r
13 import java.io.*;\r
14 import java.util.*;\r
15 \r
16 /**  This class is used to replay a request to the Services layer, by sending the XML payload\r
17  *   in an appropriate Multipart request.\r
18  *   See example usage in calling class XmlReplayTest in services/IntegrationTests, and also in main() in this class.\r
19  *   @author Laramie Crocker\r
20  */\r
21 public class XmlReplay {\r
22 \r
23     public XmlReplay(String basedir){\r
24         this.basedir = basedir;\r
25         this.serviceResultsMap = createResultsMap();\r
26     }\r
27 \r
28     public static final String DEFAULT_CONTROL = "xml-replay-control.xml";\r
29     public static final String DEFAULT_MASTER_CONTROL = "xml-replay-master.xml";\r
30 \r
31     private String basedir = ".";  //set from constructor.\r
32     public String getBaseDir(){\r
33         return basedir;\r
34     }\r
35     \r
36     private String controlFileName = DEFAULT_CONTROL;\r
37     public String getControlFileName() {\r
38         return controlFileName;\r
39     }\r
40     public void setControlFileName(String controlFileName) {\r
41         this.controlFileName = controlFileName;\r
42     }\r
43 \r
44     private String protoHostPort = "";\r
45     public String getProtoHostPort() {\r
46         return protoHostPort;\r
47     }\r
48     public void setProtoHostPort(String protoHostPort) {\r
49         this.protoHostPort = protoHostPort;\r
50     }\r
51 \r
52     private boolean autoDeletePOSTS = true;\r
53     public boolean isAutoDeletePOSTS() {\r
54         return autoDeletePOSTS;\r
55     }\r
56     public void setAutoDeletePOSTS(boolean autoDeletePOSTS) {\r
57         this.autoDeletePOSTS = autoDeletePOSTS;\r
58     }\r
59 \r
60     private Dump dump;\r
61     public Dump getDump() {\r
62         return dump;\r
63     }\r
64     public void setDump(Dump dump) {\r
65         this.dump = dump;\r
66     }\r
67 \r
68     AuthsMap defaultAuthsMap;\r
69     public AuthsMap getDefaultAuthsMap(){\r
70         return defaultAuthsMap;\r
71     }\r
72     public void setDefaultAuthsMap(AuthsMap authsMap){\r
73         defaultAuthsMap = authsMap;\r
74     }\r
75 \r
76     private Map<String, ServiceResult> serviceResultsMap;\r
77     public Map<String, ServiceResult> getServiceResultsMap(){\r
78         return serviceResultsMap;\r
79     }\r
80     public static Map<String, ServiceResult> createResultsMap(){\r
81         return new HashMap<String, ServiceResult>();\r
82     }\r
83 \r
84 \r
85     public String toString(){\r
86         return "XmlReplay{"+this.basedir+", "+this.controlFileName+", "+this.defaultAuthsMap+", "+this.dump+'}';\r
87     }\r
88 \r
89     // ============== METHODS ===========================================================\r
90 \r
91     public Document openMasterConfigFile(String masterFilename) throws FileNotFoundException {\r
92         Document document = getDocument(Tools.glue(basedir, "/", masterFilename)); //will check full path first, then checks relative to PWD.\r
93         if (document == null){\r
94             throw new FileNotFoundException("XmlReplay master control file ("+masterFilename+") not found in basedir: "+basedir+". Exiting test.");\r
95         }\r
96         return document;\r
97     }\r
98 \r
99     /** specify the master config file, relative to getBaseDir(), but ignore any tests or testGroups in the master.\r
100      *  @return a Document object, which you don't need to use: all options will be stored in XmlReplay instance.\r
101      */\r
102     public Document readOptionsFromMasterConfigFile(String masterFilename) throws FileNotFoundException {\r
103         Document document = openMasterConfigFile(masterFilename);\r
104         protoHostPort = document.selectSingleNode("/xmlReplayMaster/protoHostPort").getText().trim();\r
105         AuthsMap authsMap = readAuths(document);\r
106         setDefaultAuthsMap(authsMap);\r
107         Dump dump = XmlReplay.readDumpOptions(document);\r
108         setDump(dump);\r
109         return document;\r
110     }\r
111 \r
112     public List<List<ServiceResult>> runMaster(String masterFilename) throws Exception {\r
113         return runMaster(masterFilename, true);\r
114     }\r
115 \r
116     /** Creates new instances of XmlReplay, one for each controlFile specified in the master,\r
117      *  and setting defaults from this instance, but not sharing ServiceResult objects or maps. */\r
118     public List<List<ServiceResult>> runMaster(String masterFilename, boolean readOptionsFromMaster) throws Exception {\r
119         List<List<ServiceResult>> list = new ArrayList<List<ServiceResult>>();\r
120         Document document;\r
121         if (readOptionsFromMaster){\r
122             document = readOptionsFromMasterConfigFile(masterFilename);\r
123         } else {\r
124             document = openMasterConfigFile(masterFilename);\r
125         }\r
126         String controlFile, testGroup, test;\r
127         List<Node> runNodes;\r
128         runNodes = document.selectNodes("/xmlReplayMaster/run");\r
129         for (Node runNode : runNodes) {\r
130             controlFile = runNode.valueOf("@controlFile");\r
131             testGroup = runNode.valueOf("@testGroup");\r
132             test = runNode.valueOf("@test"); //may be empty\r
133 \r
134             //Create a new instance and clone only config values, not any results maps.\r
135             XmlReplay replay = new XmlReplay(basedir);\r
136             replay.setControlFileName(controlFile);\r
137             replay.setProtoHostPort(protoHostPort);\r
138             replay.setAutoDeletePOSTS(isAutoDeletePOSTS());\r
139             replay.setDump(dump);\r
140             replay.setDefaultAuthsMap(getDefaultAuthsMap());\r
141 \r
142             //Now run *that* instance.\r
143             List<ServiceResult> results = replay.runTests(testGroup, test);\r
144             list.add(results);\r
145         }\r
146         return list;\r
147     }\r
148 \r
149     /** Use this if you wish to named tests within a testGroup, otherwise call runTestGroup(). */\r
150     public List<ServiceResult>  runTests(String testGroupID, String testID) throws Exception {\r
151         List<ServiceResult> result = runXmlReplayFile(this.basedir,\r
152                                 this.controlFileName,\r
153                                 testGroupID,\r
154                                 testID,\r
155                                 this.serviceResultsMap,\r
156                                 this.autoDeletePOSTS,\r
157                                 dump,\r
158                                 this.protoHostPort,\r
159                                 this.defaultAuthsMap);\r
160         return result;\r
161     }\r
162 \r
163     /** Use this if you wish to specify just ONE test to run within a testGroup, otherwise call runTestGroup(). */\r
164     public ServiceResult  runTest(String testGroupID, String testID) throws Exception {\r
165         List<ServiceResult> result = runXmlReplayFile(this.basedir,\r
166                                 this.controlFileName,\r
167                                 testGroupID,\r
168                                 testID,\r
169                                 this.serviceResultsMap,\r
170                                 this.autoDeletePOSTS,\r
171                                 dump,\r
172                                 this.protoHostPort,\r
173                                 this.defaultAuthsMap);\r
174         if (result.size()>1){\r
175             throw new IndexOutOfBoundsException("Multiple ("+result.size()+") tests with ID='"+testID+"' were found within test group '"+testGroupID+"', but there should only be one test per ID attribute.");\r
176         }\r
177         return result.get(0);\r
178     }\r
179 \r
180     /** Use this if you wish to run all tests within a testGroup.*/\r
181     public List<ServiceResult> runTestGroup(String testGroupID) throws Exception {\r
182         //NOTE: calling runTest with empty testID runs all tests in a test group, but don't expose this fact.\r
183         // Expose this method (runTestGroup) instead.\r
184         return runTests(testGroupID, "");\r
185     }\r
186 \r
187     public List<ServiceResult>  autoDelete(String logName){\r
188         return autoDelete(this.serviceResultsMap, logName);\r
189     }\r
190 \r
191     /** Use this method to clean up resources created on the server that returned CSIDs, if you have\r
192      *  specified autoDeletePOSTS==false, which means you are managing the cleanup yourself.\r
193      * @param serviceResultsMap a Map of ServiceResult objects, which will contain ServiceResult.deleteURL.\r
194      * @return a List<String> of debug info about which URLs could not be deleted.\r
195      */\r
196     public static List<ServiceResult> autoDelete(Map<String, ServiceResult> serviceResultsMap, String logName){\r
197         List<ServiceResult> results = new ArrayList<ServiceResult>();\r
198         for (ServiceResult pr : serviceResultsMap.values()){\r
199             try {\r
200                 ServiceResult deleteResult = XmlReplayTransport.doDELETE(pr.deleteURL, pr.auth, pr.testID, "[autodelete:"+logName+"]");\r
201                 results.add(deleteResult);\r
202             } catch (Throwable t){\r
203                 String s = (pr!=null) ? "ERROR while cleaning up ServiceResult map: "+pr+" for "+pr.deleteURL+" :: "+t\r
204                                       : "ERROR while cleaning up ServiceResult map (null ServiceResult): "+t;\r
205                 System.err.println(s);\r
206                 ServiceResult errorResult = new ServiceResult();\r
207                 errorResult.fullURL = pr.fullURL;\r
208                 errorResult.testGroupID = pr.testGroupID;\r
209                 errorResult.fromTestID = pr.fromTestID;\r
210                 errorResult.error = s;\r
211                 results.add(errorResult);\r
212             }\r
213         }\r
214         return results;\r
215     }\r
216 \r
217     public static class AuthsMap {\r
218         Map<String,String> map;\r
219         String defaultID="";\r
220         public String getDefaultAuth(){\r
221             return map.get(defaultID);\r
222         }\r
223         public String toString(){\r
224             return "AuthsMap: {default='"+defaultID+"'; "+map.keySet()+'}';\r
225         }\r
226     }\r
227 \r
228     public static AuthsMap readAuths(Document document){\r
229     Map<String, String> map = new HashMap<String, String>();\r
230         List<Node> authNodes = document.selectNodes("//auths/auth");\r
231         for (Node auth : authNodes) {\r
232             map.put(auth.valueOf("@ID"), auth.getStringValue());\r
233         }\r
234         AuthsMap authsMap = new AuthsMap();\r
235         Node auths = document.selectSingleNode("//auths");\r
236         String defaultID = "";\r
237         if (auths != null){\r
238             defaultID = auths.valueOf("@default");\r
239         }\r
240         authsMap.map = map;\r
241         authsMap.defaultID = defaultID;\r
242         return authsMap;\r
243     }\r
244 \r
245     public static class Dump {\r
246         public boolean payloads = false;\r
247         //public static final ServiceResult.DUMP_OPTIONS dumpServiceResultOptions = ServiceResult.DUMP_OPTIONS;\r
248         public ServiceResult.DUMP_OPTIONS dumpServiceResult = ServiceResult.DUMP_OPTIONS.minimal;\r
249         public String toString(){\r
250             return "payloads: "+payloads+" dumpServiceResult: "+dumpServiceResult;\r
251         }\r
252     }\r
253 \r
254     public static Dump getDumpConfig(){\r
255         return new Dump();\r
256     }\r
257 \r
258     public static Dump readDumpOptions(Document document){\r
259         Dump dump = getDumpConfig();\r
260         Node dumpNode = document.selectSingleNode("//dump");\r
261         if (dumpNode != null){\r
262             dump.payloads = Tools.isTrue(dumpNode.valueOf("@payloads"));\r
263             String dumpServiceResultStr = dumpNode.valueOf("@dumpServiceResult");\r
264             if (Tools.notEmpty(dumpServiceResultStr)){\r
265                 dump.dumpServiceResult = ServiceResult.DUMP_OPTIONS.valueOf(dumpServiceResultStr);\r
266             }\r
267         }\r
268         return dump;\r
269     }\r
270 \r
271     private static class PartsStruct {\r
272         public List<String> partsList = new ArrayList<String>();\r
273         public List<String> filesList = new ArrayList<String>();\r
274         boolean bDoingSinglePartPayload = false;\r
275         String singlePartPayloadFilename = "";\r
276         String overrideTestID = "";\r
277         public static PartsStruct readParts(Node testNode, final String testID, String xmlReplayBaseDir){\r
278             PartsStruct result = new PartsStruct();\r
279             result.singlePartPayloadFilename = testNode.valueOf("filename");\r
280             String singlePartPayloadFilename = testNode.valueOf("filename");\r
281             if (Tools.notEmpty(singlePartPayloadFilename)){\r
282                 result.bDoingSinglePartPayload = true;\r
283                 result.singlePartPayloadFilename = xmlReplayBaseDir + '/' + singlePartPayloadFilename;\r
284             } else {\r
285                 result.bDoingSinglePartPayload = false;\r
286                 List<Node> parts = testNode.selectNodes("parts/part");\r
287                 if (parts == null || parts.size()==0){  //path is just /testGroup/test/part/\r
288                     String commonPartName = testNode.valueOf("part/label");\r
289                     String testfile = testNode.valueOf("part/filename");\r
290                     String fullTestFilename = xmlReplayBaseDir + '/' + testfile;\r
291                     if ( Tools.isEmpty(testID) ){\r
292                         result.overrideTestID = testfile; //It is legal to have a missing ID attribute, and rely on a unique filename.\r
293                     }\r
294                     result.partsList.add(commonPartName);\r
295                     result.filesList.add(fullTestFilename);\r
296                 } else { // path is /testGroup/test/parts/part/\r
297                     for (Node part : parts){\r
298                         String commonPartName = part.valueOf("label");\r
299                         String filename = part.valueOf("filename");\r
300                         String fullTestFilename = xmlReplayBaseDir + '/' + filename;\r
301                         if ( Tools.isEmpty(testID) ){  //if testID is empty, we'll use the *first*  filename as ID.\r
302                             result.overrideTestID = filename; //It is legal to have a missing ID attribute, and rely on a unique filename.\r
303                         }\r
304                         result.partsList.add(commonPartName);\r
305                         result.filesList.add(fullTestFilename);\r
306                     }\r
307                 }\r
308             }\r
309             return result;\r
310         }\r
311     }\r
312 \r
313     private static String fixupFullURL(String fullURL, String protoHostPort, String uri){\r
314         if ( ! uri.startsWith(protoHostPort)){\r
315             fullURL = Tools.glue(protoHostPort, "/", uri);\r
316         } else {\r
317             fullURL = uri;\r
318         }\r
319         return fullURL;\r
320     }\r
321 \r
322     private static String fromTestID(String fullURL, Node testNode, Map<String, ServiceResult> serviceResultsMap){\r
323         String fromTestID = testNode.valueOf("fromTestID");\r
324         if (Tools.notEmpty(fromTestID)){\r
325             ServiceResult getPR = serviceResultsMap.get(fromTestID);\r
326             if (getPR != null){\r
327                 fullURL = Tools.glue(fullURL, "/", getPR.location);\r
328             }\r
329         }\r
330         return fullURL;\r
331     }\r
332 \r
333     private static String CSIDfromTestID(Node testNode, Map<String, ServiceResult> serviceResultsMap){\r
334         String result = "";\r
335         String fromTestID = testNode.valueOf("fromTestID");\r
336         if (Tools.notEmpty(fromTestID)){\r
337             ServiceResult getPR = serviceResultsMap.get(fromTestID);\r
338             if (getPR != null){\r
339                 result = getPR.location;\r
340             }\r
341         }\r
342         return result;\r
343     }\r
344 \r
345 \r
346     public static org.dom4j.Document getDocument(String xmlFileName) {\r
347         Document document = null;\r
348         SAXReader reader = new SAXReader();\r
349         try {\r
350             document = reader.read(xmlFileName);\r
351         } catch (DocumentException e) {\r
352             //e.printStackTrace();\r
353         }\r
354         return document;\r
355     }\r
356 \r
357 \r
358     //================= runXmlReplayFile ======================================================\r
359 \r
360     public static List<ServiceResult> runXmlReplayFile(String xmlReplayBaseDir,\r
361                                           String controlFileName,\r
362                                           String testGroupID,\r
363                                           String oneTestID,\r
364                                           Map<String, ServiceResult> serviceResultsMap,\r
365                                           boolean param_autoDeletePOSTS,\r
366                                           Dump dump,\r
367                                           String protoHostPortParam,\r
368                                           AuthsMap defaultAuths)\r
369                                           throws Exception {\r
370         //Internally, we maintain two collections of ServiceResult:\r
371         //  the first is the return value of this method.\r
372         //  the second is the serviceResultsMap, which is used for keeping track of CSIDs created by POSTs, for later reference by DELETE, etc.\r
373         List<ServiceResult> results = new ArrayList<ServiceResult>();\r
374 \r
375         String controlFile = Tools.glue(xmlReplayBaseDir, "/", controlFileName);\r
376         Document document;\r
377         document = getDocument(controlFile); //will check full path first, then checks relative to PWD.\r
378         if (document==null){\r
379             throw new FileNotFoundException("XmlReplay control file ("+controlFileName+") not found in basedir: "+xmlReplayBaseDir+" Exiting test.");\r
380         }\r
381         String protoHostPort;\r
382         if (Tools.isEmpty(protoHostPortParam)){\r
383             protoHostPort = document.selectSingleNode("/xmlReplay/protoHostPort").getText().trim();\r
384             System.out.println("DEPRECATED: Using protoHostPort ('"+protoHostPort+"') from xmlReplay file ('"+controlFile+"'), not master.");\r
385         } else {\r
386             protoHostPort = protoHostPortParam;\r
387         }\r
388         if (Tools.isEmpty(protoHostPort)){\r
389             throw new Exception("XmlReplay control file must have a protoHostPort element");\r
390         }\r
391 \r
392         String authsMapINFO;\r
393         AuthsMap authsMap = readAuths(document);\r
394         if (authsMap.map.size()==0){\r
395             authsMap = defaultAuths;\r
396             authsMapINFO = "Using defaultAuths from master file: "+defaultAuths;\r
397         } else {\r
398             authsMapINFO = "Using AuthsMap from control file: "+authsMap;\r
399         }\r
400         System.out.println("XmlReplay running:"\r
401                           +"\r\n   controlFile: "+ (new File(controlFile).getCanonicalPath())\r
402                           +"\r\n   protoHostPort: "+protoHostPort\r
403                           +"\r\n   testGroup: "+testGroupID\r
404                           + (Tools.notEmpty(oneTestID) ? "\r\n   oneTestID: "+oneTestID : "")\r
405                           +"\r\n   AuthsMap: "+authsMapINFO\r
406                           +"\r\n   param_autoDeletePOSTS: "+param_autoDeletePOSTS\r
407                           +"\r\n   Dump info: "+dump\r
408                           +"\r\n");\r
409 \r
410         String autoDeletePOSTS = "";\r
411         List<Node> testgroupNodes;\r
412         if (Tools.notEmpty(testGroupID)){\r
413             testgroupNodes = document.selectNodes("//testGroup[@ID='"+testGroupID+"']");\r
414         } else {\r
415             testgroupNodes = document.selectNodes("//testGroup");\r
416         }\r
417 \r
418         JexlEngine jexl = new JexlEngine();   // Used for expression language expansion from uri field.\r
419         XmlReplayEval evalStruct = new XmlReplayEval();\r
420         evalStruct.serviceResultsMap = serviceResultsMap;\r
421         evalStruct.jexl = jexl;\r
422 \r
423         for (Node testgroup : testgroupNodes) {\r
424             JexlContext jc = new MapContext();  //Get a new JexlContext for each test group.\r
425             evalStruct.jc = jc;\r
426 \r
427             autoDeletePOSTS = testgroup.valueOf("@autoDeletePOSTS");\r
428             List<Node> tests;\r
429             if (Tools.notEmpty(oneTestID)){\r
430                 tests = testgroup.selectNodes("test[@ID='"+oneTestID+"']");\r
431             } else {\r
432                 tests = testgroup.selectNodes("test");\r
433             }\r
434             String authForTest = "";\r
435             int testElementIndex = -1;\r
436 \r
437             for (Node testNode : tests) {\r
438                 testElementIndex++;\r
439                 String testID = testNode.valueOf("@ID");\r
440                 String testIDLabel = Tools.notEmpty(testID) ? (testGroupID+'.'+testID) : (testGroupID+'.'+testElementIndex);\r
441                 String method = testNode.valueOf("method");\r
442                 String uri = testNode.valueOf("uri");\r
443                 String fullURL = Tools.glue(protoHostPort, "/", uri);\r
444                 String initURI = uri;\r
445 \r
446                 String authIDForTest = testNode.valueOf("@auth");\r
447                 String currentAuthForTest = authsMap.map.get(authIDForTest);\r
448                 if (Tools.notEmpty(currentAuthForTest)){\r
449                     authForTest = currentAuthForTest; //else just run with current from last loop;\r
450                 }\r
451                 if (Tools.isEmpty(authForTest)){\r
452                     authForTest = defaultAuths.getDefaultAuth();\r
453                 }\r
454 \r
455                 if (uri.indexOf("$")>-1){\r
456                     uri = evalStruct.eval(uri, serviceResultsMap, jexl, jc);\r
457                 }\r
458                 fullURL = fixupFullURL(fullURL, protoHostPort, uri);\r
459 \r
460                 List<Integer> expectedCodes = new ArrayList<Integer>();\r
461                 String expectedCodesStr = testNode.valueOf("expectedCodes");\r
462                 if (Tools.notEmpty(expectedCodesStr)){\r
463                      String[] codesArray = expectedCodesStr.split(",");\r
464                      for (String code : codesArray){\r
465                          expectedCodes.add(new Integer(code));\r
466                      }\r
467                 }\r
468 \r
469                 ServiceResult serviceResult;\r
470                 boolean isPOST = method.equalsIgnoreCase("POST");\r
471                 boolean isPUT =  method.equalsIgnoreCase("PUT");\r
472                 if ( isPOST || isPUT ) {\r
473                     PartsStruct parts = PartsStruct.readParts(testNode, testID, xmlReplayBaseDir);\r
474                     if (Tools.notEmpty(parts.overrideTestID)) {\r
475                         testID = parts.overrideTestID;\r
476                     }\r
477                     if (isPOST){\r
478                         String csid = CSIDfromTestID(testNode, serviceResultsMap);\r
479                         if (Tools.notEmpty(csid)) uri = Tools.glue(uri, "/", csid+"/items/");\r
480                     } else if (isPUT) {\r
481                         uri = fromTestID(uri, testNode, serviceResultsMap);\r
482                     }\r
483                     if (parts.bDoingSinglePartPayload){\r
484                         serviceResult = XmlReplayTransport.doPOST_PUTFromXML(parts.singlePartPayloadFilename, protoHostPort, uri, "POST", XmlReplayTransport.APPLICATION_XML, evalStruct, authForTest, testIDLabel);\r
485                     } else {\r
486                         serviceResult = XmlReplayTransport.doPOST_PUTFromXML_Multipart(parts.filesList, parts.partsList, protoHostPort, uri, "POST", evalStruct, authForTest, testIDLabel);\r
487                     }\r
488                     results.add(serviceResult);\r
489                     if (isPOST){\r
490                         serviceResultsMap.put(testID, serviceResult);      //PUTs do not return a Location, so don't add PUTs to serviceResultsMap.\r
491                     }\r
492                     fullURL = fixupFullURL(fullURL, protoHostPort, uri);\r
493                 } else if (method.equalsIgnoreCase("DELETE")){\r
494                     String fromTestID = testNode.valueOf("fromTestID");\r
495                     ServiceResult pr = serviceResultsMap.get(fromTestID);\r
496                     if (pr!=null){\r
497                         serviceResult = XmlReplayTransport.doDELETE(pr.deleteURL, authForTest, testIDLabel, fromTestID);\r
498                         serviceResult.fromTestID = fromTestID;\r
499                         results.add(serviceResult);\r
500                         if (serviceResult.gotExpectedResult()){\r
501                             serviceResultsMap.remove(fromTestID);\r
502                         }\r
503                     } else {\r
504                         if (Tools.notEmpty(fromTestID)){\r
505                             serviceResult = new ServiceResult();\r
506                             serviceResult.responseCode = 0;\r
507                             serviceResult.error = "ID not found in element fromTestID: "+fromTestID;\r
508                             System.err.println("****\r\nServiceResult: "+serviceResult.error+". SKIPPING TEST. Full URL: "+fullURL);\r
509                         } else {\r
510                             serviceResult = XmlReplayTransport.doDELETE(fullURL, authForTest, testID, fromTestID);\r
511                         }\r
512                         serviceResult.fromTestID = fromTestID;\r
513                         results.add(serviceResult);\r
514                     }\r
515                 } else if (method.equalsIgnoreCase("GET")){\r
516                     fullURL = fromTestID(fullURL, testNode, serviceResultsMap);\r
517                     serviceResult = XmlReplayTransport.doGET(fullURL, authForTest, testIDLabel);\r
518                     results.add(serviceResult);\r
519                 } else if (method.equalsIgnoreCase("LIST")){\r
520                     fullURL = fixupFullURL(fullURL, protoHostPort, uri);\r
521                     String listQueryParams = ""; //TODO: empty for now, later may pick up from XML control file.\r
522                     serviceResult = XmlReplayTransport.doLIST(fullURL, listQueryParams, authForTest, testIDLabel);\r
523                     results.add(serviceResult);\r
524                 } else {\r
525                     throw new Exception("HTTP method not supported by XmlReplay: "+method);\r
526                 }\r
527 \r
528                 serviceResult.testID = testID;\r
529                 serviceResult.fullURL = fullURL;\r
530                 serviceResult.auth = authForTest;\r
531                 serviceResult.method = method;\r
532                 if (expectedCodes.size()>0){\r
533                     serviceResult.expectedCodes = expectedCodes;\r
534                 }\r
535                 if (Tools.isEmpty(serviceResult.testID)) serviceResult.testID = testIDLabel;\r
536                 if (Tools.isEmpty(serviceResult.testGroupID)) serviceResult.testGroupID = testGroupID;\r
537 \r
538                 String serviceResultRow = serviceResult.dump(dump.dumpServiceResult);\r
539                 String leader = (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.detailed) ? "XmlReplay:"+testIDLabel+": ": "";\r
540                 System.out.println(leader+serviceResultRow+"\r\n");\r
541                 if (dump.payloads) System.out.println(serviceResult.result);\r
542             }\r
543             if (Tools.isTrue(autoDeletePOSTS)&&param_autoDeletePOSTS){\r
544                 autoDelete(serviceResultsMap, "default");\r
545             }\r
546         }\r
547         return results;\r
548     }\r
549 \r
550 \r
551     //======================== MAIN ===================================================================\r
552 \r
553     private static Options createOptions() {\r
554         Options options = new Options();\r
555         options.addOption("xmlReplayBaseDir", true, "default/basedir");\r
556         return options;\r
557     }\r
558 \r
559     public static String usage(){\r
560         String result = "org.collectionspace.services.IntegrationTests.xmlreplay.XmlReplay {args}\r\n"\r
561                         +"  -xmlReplayBaseDir <dir> \r\n"\r
562                         +" You may also override these with system args, e.g.: \r\n"\r
563                         +"   -DxmlReplayBaseDir=/path/to/dir \r\n"\r
564                         +" These may also be passed in via the POM.\r\n"\r
565                         +" You can also set these system args, e.g.: \r\n"\r
566                         +"  -DtestGroupID=<oneID> \r\n"\r
567                         +"  -DtestID=<one TestGroup ID>"\r
568                         +"  -DautoDeletePOSTS=<true|false> \r\n"\r
569                         +"    (note: -DautoDeletePOSTS won't force deletion if set to false in control file.";\r
570         return result;\r
571     }\r
572 \r
573     private static String opt(CommandLine line, String option){\r
574         String result;\r
575         String fromProps = System.getProperty(option);\r
576         if (Tools.notEmpty(fromProps)){\r
577             return fromProps;\r
578         }\r
579         result = line.getOptionValue(option);\r
580         if (result == null){\r
581             result = "";\r
582         }\r
583         return result;\r
584     }\r
585 \r
586     public static void main(String[]args) throws Exception {\r
587         Options options = createOptions();\r
588         //System.out.println("System CLASSPATH: "+prop.getProperty("java.class.path", null));\r
589         CommandLineParser parser = new GnuParser();\r
590         try {\r
591             // parse the command line arguments\r
592             CommandLine line = parser.parse(options, args);\r
593 \r
594             String xmlReplayBaseDir = opt(line, "xmlReplayBaseDir");\r
595             String testGroupID      = opt(line, "testGroupID");\r
596             String testID           = opt(line, "testID");\r
597             String autoDeletePOSTS  = opt(line, "autoDeletePOSTS");\r
598             String dumpResults      = opt(line, "dumpResults");\r
599             String controlFilename   = opt(line, "controlFilename");\r
600             String xmlReplayMaster  = opt(line, "xmlReplayMaster");\r
601 \r
602             xmlReplayBaseDir = Tools.fixFilename(xmlReplayBaseDir);\r
603             controlFilename = Tools.fixFilename(controlFilename);\r
604 \r
605             boolean bAutoDeletePOSTS = true;\r
606             if (Tools.notEmpty(autoDeletePOSTS)) {\r
607                 bAutoDeletePOSTS = Tools.isTrue(autoDeletePOSTS);\r
608             }\r
609             boolean bDumpResults = false;\r
610             if (Tools.notEmpty(dumpResults)) {\r
611                 bDumpResults = Tools.isTrue(autoDeletePOSTS);\r
612             }\r
613             if (Tools.isEmpty(xmlReplayBaseDir)){\r
614                 System.err.println("ERROR: xmlReplayBaseDir was not specified.");\r
615                 return;\r
616             }\r
617             File f = new File(Tools.glue(xmlReplayBaseDir, "/", controlFilename));\r
618             if (Tools.isEmpty(xmlReplayMaster) && !f.exists()){\r
619                 System.err.println("Control file not found: "+f.getCanonicalPath());\r
620                 return;\r
621             }\r
622             File fMaster = new File(Tools.glue(xmlReplayBaseDir, "/", xmlReplayMaster));\r
623             if (Tools.notEmpty(xmlReplayMaster)  && !fMaster.exists()){\r
624                 System.err.println("Master file not found: "+fMaster.getCanonicalPath());\r
625                 return;\r
626             }\r
627 \r
628             String xmlReplayBaseDirResolved = (new File(xmlReplayBaseDir)).getCanonicalPath();\r
629             System.out.println("XmlReplay ::"\r
630                             + "\r\n    xmlReplayBaseDir: "+xmlReplayBaseDir\r
631                             + "\r\n    xmlReplayBaseDir(resolved): "+xmlReplayBaseDirResolved\r
632                             + "\r\n    controlFilename: "+controlFilename\r
633                             + "\r\n    xmlReplayMaster: "+xmlReplayMaster\r
634                             + "\r\n    testGroupID: "+testGroupID\r
635                             + "\r\n    testID: "+testID\r
636                             + "\r\n    autoDeletePOSTS: "+bAutoDeletePOSTS\r
637                             + (Tools.notEmpty(xmlReplayMaster)\r
638                                        ? ("\r\n    will use master file: "+fMaster.getCanonicalPath())\r
639                                        : ("\r\n    will use control file: "+f.getCanonicalPath()) )\r
640                              );\r
641             \r
642             if (Tools.notEmpty(xmlReplayMaster)){\r
643                 if (Tools.notEmpty(controlFilename)){\r
644                     System.out.println("WARN: controlFilename: "+controlFilename+" will not be used because master was specified.  Running master: "+xmlReplayMaster);\r
645                 }\r
646                 XmlReplay replay = new XmlReplay(xmlReplayBaseDirResolved);\r
647                 replay.readOptionsFromMasterConfigFile(xmlReplayMaster);\r
648                 replay.setAutoDeletePOSTS(bAutoDeletePOSTS);\r
649                 Dump dumpFromMaster = replay.getDump();\r
650                 dumpFromMaster.payloads = Tools.isTrue(dumpResults);\r
651                 replay.setDump(dumpFromMaster);\r
652                 replay.runMaster(xmlReplayMaster, false); //false, because we already just read the options, and override a few.\r
653             } else {\r
654                 Dump dump = getDumpConfig();\r
655                 dump.payloads = Tools.isTrue(dumpResults);\r
656                 runXmlReplayFile(xmlReplayBaseDirResolved, controlFilename, testGroupID, testID, createResultsMap(), bAutoDeletePOSTS, dump, "", null);\r
657             }\r
658         } catch (ParseException exp) {\r
659             // oops, something went wrong\r
660             System.err.println("Cmd-line parsing failed.  Reason: " + exp.getMessage());\r
661             System.err.println(usage());\r
662         } catch (Exception e) {\r
663             System.out.println("Error : " + e.getMessage());\r
664             e.printStackTrace();\r
665         }\r
666     }\r
667 \r
668 }\r