/*
* Copyright 2012 Splunk, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"): you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.splunk;
import com.google.gson.Gson;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;
import static junit.framework.TestCase.*;
/**
* Test the parsing of XML from results endpoints.
*
* All the raw XML to parse is in the data/results/ directory, and the expected
* behavior is specified in the data/resultsreader_test_data.json file.
*/
@RunWith(Parameterized.class)
public class ResultsReaderTestFromExpectedFile {
private static Gson reader = new Gson();
private static Map<String, Object> expectedData =
reader.fromJson(
SDKTestCase.streamToString(
SDKTestCase.openResource(
"data/resultsreader_test_data.json")),
Map.class);
private Map<String, Object> expectedResultsSet;
private String version;
private String testName;
private InputStream xmlStream;
public ResultsReaderTestFromExpectedFile(String version, String testName) {
this.version = version;
this.testName = testName;
this.xmlStream = SDKTestCase.openResource(
"data/results/" + version + "/" + testName + ".xml");
Map<String, Object> versionData =
(Map<String, Object>)expectedData.get(version);
this.expectedResultsSet =
(Map<String, Object>)versionData.get(testName);
}
@Parameterized.Parameters(name="{1} from version {0}")
public static Collection<Object[]> testCases() {
Collection<Object[]> cases = new ArrayList<Object[]>();
for (String version : (Set<String>)expectedData.keySet()) {
Map<String, Object> casesForThisVersion =
(Map<String, Object>)expectedData.get(version);
for (String testName : (Set<String>)casesForThisVersion.keySet()) {
cases.add(new Object[] {version, testName});
}
}
return cases;
}
@Test
public void testResultsReader() throws IOException, XMLStreamException {
// TODO: This test fails on Windows due to XML attributes being out of order
ResultsReaderXml resultsReader = new ResultsReaderXml(this.xmlStream);
List<Map<String, Object>> expectedEvents =
(List<Map<String, Object>>)this.expectedResultsSet.get("results");
verifyResultsReader(resultsReader, expectedEvents);
}
static String xmlToString(String originalXml) throws Exception
{
DocumentBuilderFactory fctr = DocumentBuilderFactory.newInstance();
DocumentBuilder bldr = fctr.newDocumentBuilder();
InputSource insrc = new InputSource(new StringReader(originalXml));
Document xml = bldr.parse(insrc);
xml.normalize();
DOMSource domSource = new DOMSource(xml);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
static void verifyResultsReader(
ResultsReaderXml resultsReader,
List<Map<String, Object>> expectedEvents)
throws IOException, XMLStreamException {
for (Map<String, Object> expectedEvent : expectedEvents) {
Event foundEvent = resultsReader.getNextEvent();
assertNotNull(
"Did not parse as many events from the XML as expected.",
foundEvent);
if (foundEvent.containsKey("_raw")) {
final String segmentedRaw = foundEvent.getSegmentedRaw();
final String keySegmentedRaw = "RAW_XML";
try {
final String parsedExpected = xmlToString((String)expectedEvent.get(keySegmentedRaw));
final String parsedReceived = xmlToString(segmentedRaw);
assertEquals(parsedExpected, parsedReceived);
} catch (Exception e) {
// TODO Auto-generated catch block
assertFalse(true);
}
verifyXml(segmentedRaw);
}
Map<String, Object> expectedFields =
(Map<String,Object>)expectedEvent.get("fields");
Set<String> expectedKeys = expectedFields.keySet();
assertEquals(expectedKeys, foundEvent.keySet());
for (String key : expectedFields.keySet()) {
assertTrue(foundEvent.containsKey(key));
if (expectedFields.get(key) instanceof List) {
assertEquals(
expectedFields.get(key),
Arrays.asList(foundEvent.getArray(key)));
} else {
assertEquals(expectedFields.get(key), foundEvent.get(key));
}
}
}
assertNull(resultsReader.getNextEvent());
}
// Verify XML by round-tripping.
static private void verifyXml(String xml)
throws XMLStreamException, IOException {
ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(xml.getBytes());
XMLEventReader reader = XMLInputFactory.newInstance().
createXMLEventReader(byteArrayInputStream);
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream();
XMLEventWriter writer = XMLOutputFactory.newInstance().
createXMLEventWriter(byteArrayOutputStream);
writer.add(reader);
writer.close();
String xmlWithDtd = byteArrayOutputStream.toString();
int lengthOfDtd = xmlWithDtd.indexOf(">") + 1;
String dtd = xmlWithDtd.substring(0, lengthOfDtd);
assertTrue("Expected xml to have a DTD", dtd.startsWith("<?"));
// Remove the XML DTD
String xmlWithoutDtd = xmlWithDtd.substring(lengthOfDtd);
assertEquals(xml, xmlWithoutDtd);
byteArrayInputStream.close();
}
}