/* // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. // You must accept the terms of that agreement to use this software. // // Copyright (C) 2002-2014 Pentaho and others // All Rights Reserved. */ package mondrian.xmla.test; import mondrian.olap.*; import mondrian.olap.Util.PropertyList; import mondrian.rolap.RolapConnectionProperties; import mondrian.server.StringRepositoryContentFinder; import mondrian.test.DiffRepository; import mondrian.test.TestContext; import mondrian.xmla.*; import mondrian.xmla.impl.DefaultXmlaRequest; import mondrian.xmla.impl.DefaultXmlaResponse; import junit.framework.*; import org.apache.log4j.Logger; import org.custommonkey.xmlunit.XMLAssert; import org.custommonkey.xmlunit.XMLUnit; import org.w3c.dom.*; import java.io.*; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; /** * Unit test for refined Mondrian's XML for Analysis API (package * {@link mondrian.xmla}). * * @author Gang Chen */ public class XmlaTest extends TestCase { private static final Logger LOGGER = Logger.getLogger(XmlaTest.class); static { XMLUnit.setControlParser( "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); XMLUnit.setTestParser( "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); XMLUnit.setIgnoreWhitespace(true); } private static final XmlaTestContext context = new XmlaTestContext(); private static final String DATA_SOURCE_INFO_RESPONSE_PROP = "data.source.info.response"; private XmlaHandler handler; private MondrianServer server; public XmlaTest(String name) { super(name); } // implement TestCase protected void setUp() throws Exception { super.setUp(); DiffRepository diffRepos = getDiffRepos(); diffRepos.setCurrentTestCaseName(getName()); server = MondrianServer.createWithRepository( new StringRepositoryContentFinder( context.getDataSourcesString()), XmlaTestContext.CATALOG_LOCATOR); handler = new XmlaHandler( (XmlaHandler.ConnectionFactory) server, "xmla"); XMLUnit.setIgnoreWhitespace(false); } // implement TestCase protected void tearDown() throws Exception { DiffRepository diffRepos = getDiffRepos(); diffRepos.setCurrentTestCaseName(null); server.shutdown(); server = null; handler = null; super.tearDown(); } private static DiffRepository getDiffRepos() { return DiffRepository.lookup(XmlaTest.class); } protected void runTest() throws Exception { if (!MondrianProperties.instance().SsasCompatibleNaming.get() && getName().equals("mdschemaLevelsCubeDimRestrictions")) { // Changes in unique names of hierarchies and levels mean that the // output is a different order in the old behavior, and cannot be // fixed by a few sed-like comparisons. return; } DiffRepository diffRepos = getDiffRepos(); String request = diffRepos.expand(null, "${request}"); String expectedResponse = diffRepos.expand(null, "${response}"); Properties props = new Properties(); XmlaTestContext s = new XmlaTestContext(); String con = s.getConnectString().replaceAll("&","&"); PropertyList pl = Util.parseConnectString(con); pl.remove(RolapConnectionProperties.Jdbc.name()); pl.remove(RolapConnectionProperties.JdbcUser.name()); pl.remove(RolapConnectionProperties.JdbcPassword.name()); props.setProperty(DATA_SOURCE_INFO_RESPONSE_PROP, pl.toString()); expectedResponse = Util.replaceProperties( expectedResponse, Util.toMap(props)); Element requestElem = XmlaUtil.text2Element( XmlaTestContext.xmlFromTemplate( request, XmlaTestContext.ENV)); Element responseElem = ignoreLastUpdateDate(executeRequest(requestElem)); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); StringWriter bufWriter = new StringWriter(); transformer.transform( new DOMSource(responseElem), new StreamResult(bufWriter)); bufWriter.write(Util.nl); String actualResponse = TestContext.instance().upgradeActual( bufWriter.getBuffer().toString()); try { // Start with a purely logical XML diff to avoid test noise // from non-determinism in XML generation. XMLAssert.assertXMLEqual(expectedResponse, actualResponse); } catch (AssertionFailedError e) { // In case of failure, re-diff using DiffRepository's comparison // method. It may have noise due to physical vs logical structure, // but it will maintain the expected/actual, and some IDEs can even // display visual diffs. diffRepos.assertEquals("response", "${response}", actualResponse); } } private Element ignoreLastUpdateDate(Element element) { NodeList elements = element.getElementsByTagName("LAST_SCHEMA_UPDATE"); for (int i = elements.getLength(); i > 0; i--) { blankNode(elements.item(i - 1)); } return element; } private void blankNode(Node node) { node.setTextContent(""); } private Element executeRequest(Element requestElem) { ByteArrayOutputStream resBuf = new ByteArrayOutputStream(); XmlaRequest request = new DefaultXmlaRequest(requestElem, null, null, null, null); XmlaResponse response = new DefaultXmlaResponse( resBuf, "UTF-8", Enumeration.ResponseMimeType.SOAP); handler.process(request, response); return XmlaUtil.stream2Element( new ByteArrayInputStream(resBuf.toByteArray())); } public static TestSuite suite() { TestSuite suite = new TestSuite(); DiffRepository diffRepos = getDiffRepos(); MondrianProperties properties = MondrianProperties.instance(); String filePattern = properties.QueryFilePattern.get(); final Pattern pattern = filePattern == null ? null : Pattern.compile(filePattern); List<String> testCaseNames = diffRepos.getTestCaseNames(); if (pattern != null) { Iterator<String> iter = testCaseNames.iterator(); while (iter.hasNext()) { String name = iter.next(); if (!pattern.matcher(name).matches()) { iter.remove(); } } } LOGGER.debug("Found " + testCaseNames.size() + " XML/A test cases"); for (String name : testCaseNames) { suite.addTest(new XmlaTest(name)); } suite.addTestSuite(OtherTest.class); return suite; } /** * Non diff-based unit tests for XML/A support. */ public static class OtherTest extends TestCase { public void testEncodeElementName() { final XmlaUtil.ElementNameEncoder encoder = XmlaUtil.ElementNameEncoder.INSTANCE; assertEquals("Foo", encoder.encode("Foo")); assertEquals("Foo_x0020_Bar", encoder.encode("Foo Bar")); if (false) // FIXME: assertEquals( "Foo_x00xx_Bar", encoder.encode("Foo_Bar")); // Caching: decode same string, get same string back final String s1 = encoder.encode("Abc def"); final String s2 = encoder.encode("Abc def"); assertSame(s1, s2); } /** * Unit test for {@link XmlaUtil#chooseResponseMimeType(String)}. */ public void testAccept() { // simple assertEquals( Enumeration.ResponseMimeType.SOAP, XmlaUtil.chooseResponseMimeType("application/xml")); // deal with ",q=<n>" quality codes by ignoring them assertEquals( Enumeration.ResponseMimeType.SOAP, XmlaUtil.chooseResponseMimeType( "text/html,application/xhtml+xml," + "application/xml;q=0.9,*/*;q=0.8")); // return null if nothing matches assertNull( XmlaUtil.chooseResponseMimeType( "text/html,application/xhtml+xml")); // quality codes all over the place; return JSON because we see // it before application/xml assertEquals( Enumeration.ResponseMimeType.JSON, XmlaUtil.chooseResponseMimeType( "text/html;q=0.9," + "application/xhtml+xml;q=0.9," + "application/json;q=0.9," + "application/xml;q=0.9," + "*/*;q=0.8")); // allow application/soap+xml as synonym for application/xml assertEquals( Enumeration.ResponseMimeType.SOAP, XmlaUtil.chooseResponseMimeType( "text/html,application/soap+xml")); // allow text/xml as synonym for application/xml assertEquals( Enumeration.ResponseMimeType.SOAP, XmlaUtil.chooseResponseMimeType( "text/html,application/soap+xml")); } } } // End XmlaTest.java