diff --git a/src/org/olap4j/OlapDatabaseMetaData.java b/src/org/olap4j/OlapDatabaseMetaData.java index 9369a69..d9b14a4 100644 --- a/src/org/olap4j/OlapDatabaseMetaData.java +++ b/src/org/olap4j/OlapDatabaseMetaData.java @@ -107,7 +107,8 @@ ResultSet getActions( /** * Retrives a list of olap4j data sources that are available on the server. * - *

Specification as for XML/A DISCOVER_DATASOURCES schema rowset. + *

Specification as for XML/A DISCOVER_DATASOURCES schema rowset. The + * rows are ordered by DATA_SOURCE_NAME. * *

    *
  1. DATA_SOURCE_NAME String => The name of the data source, such diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index c57e661..04011dd 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -840,14 +840,15 @@ public String generateRequest( } // If the request requires catalog name, and one wasn't specified in the - // restrictions, use the connection's current catalog. - if (context.olap4jCatalog != null) { - requestCatalogName = context.olap4jCatalog.getName(); + // restrictions, use the connection's current schema. (Note: What XMLA + // calls a catalog, JDBC calls a schema.) + if (context.olap4jSchema != null) { + requestCatalogName = context.olap4jSchema.getName(); } if (requestCatalogName == null && metadataRequest.requiresCatalogName()) { - requestCatalogName = context.olap4jConnection.getCatalog(); + requestCatalogName = context.olap4jConnection.getSchema().getName(); } // Add the catalog node only if this request has specified it as a diff --git a/test.properties b/test.properties index 6db4fd5..b468a06 100644 --- a/test.properties +++ b/test.properties @@ -27,7 +27,7 @@ # a different database, edit the jdbc.properties file # in the /simple-jndi folder. -org.olap4j.test.helperClassName=org.olap4j.MondrianTester +org.olap4j.test.helperClassName=mondrian.test.MondrianOlap4jTester org.olap4j.test.connectUrl=jdbc:mondrian:Datasource=jdbc/SampleData;Catalog=./foodmart/FoodMart.xml; ############################################################################### diff --git a/testsrc/org/olap4j/CellSetFormatterTest.java b/testsrc/org/olap4j/CellSetFormatterTest.java index e1ba11b..259946a 100644 --- a/testsrc/org/olap4j/CellSetFormatterTest.java +++ b/testsrc/org/olap4j/CellSetFormatterTest.java @@ -31,7 +31,9 @@ * @version $Id$ */ public class CellSetFormatterTest extends TestCase { - final String query1 = + final TestContext.Tester tester = TestContext.instance().getTester(); + + static final String query1 = "select\n" + " crossjoin(\n" + " {[Time].[1997].[Q1], [Time].[1997].[Q2].[4]},\n" @@ -55,7 +57,6 @@ private void assertFormat( Format format, String expected) throws SQLException { - final TestContext.Tester tester = TestContext.instance().getTester(); Connection connection = null; try { connection = tester.createConnection(); diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index 96140f6..8392a5a 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -31,8 +31,8 @@ * Unit test for olap4j Driver and Connection classes. * *

    The system property "org.olap4j.test.helperClassName" determines the - * name of the helper class. By default, uses {@link MondrianTester}, which - * runs against mondrian; {@link XmlaTester} is also available. + * name of the helper class. By default, uses {@link org.olap4j.XmlaTester}, + * use the XMLA driver. * * @author jhyde * @version $Id$ @@ -1905,28 +1905,23 @@ public void testMetadata() throws Exception { assertEquals("Food", member.getCaption()); - if (tester.getFlavor() != Tester.Flavor.XMLA - && tester.getFlavor() != Tester.Flavor.REMOTE_XMLA) - { + switch (tester.getFlavor()) { + case XMLA: + case REMOTE_XMLA: + assertEquals("", member.getDescription()); + assertEquals(204, member.getOrdinal()); + break; + default: assertNull(member.getDescription()); + assertEquals(-1, member.getOrdinal()); assertEquals(1, member.getDepth()); assertEquals(-1, member.getSolveOrder()); assertFalse(member.isHidden()); assertNull(member.getDataMember()); assertFalse(member.isCalculatedInQuery()); - } else { - assertEquals("", member.getDescription()); - } - - switch (tester.getFlavor()) { - case MONDRIAN: - // mondrian does not set ordinals correctly - assertEquals(-1, member.getOrdinal()); - break; - default: - assertEquals(204, member.getOrdinal()); break; } + final NamedList propertyList = member.getProperties(); assertEquals(25, propertyList.size()); final Property property = propertyList.get("MEMBER_CAPTION"); diff --git a/testsrc/org/olap4j/MetadataTest.java b/testsrc/org/olap4j/MetadataTest.java index 3b68431..52e70b2 100644 --- a/testsrc/org/olap4j/MetadataTest.java +++ b/testsrc/org/olap4j/MetadataTest.java @@ -251,13 +251,13 @@ public void testDatabaseMetaDataGetDatasources() throws SQLException { switch (tester.getFlavor()) { case MONDRIAN: TestContext.assertEqualsVerbose( - "DATA_SOURCE_NAME=xxx," + "DATA_SOURCE_NAME=FoodMart," + " DATA_SOURCE_DESCRIPTION=null," + " URL=null," - + " DATA_SOURCE_INFO=xxx," - + " PROVIDER_NAME=null," + + " DATA_SOURCE_INFO=FoodMart," + + " PROVIDER_NAME=Mondrian," + " PROVIDER_TYPE=MDP," - + " AUTHENTICATION_MODE=null\n", + + " AUTHENTICATION_MODE=Unauthenticated\n", s); break; case REMOTE_XMLA: @@ -265,10 +265,17 @@ public void testDatabaseMetaDataGetDatasources() throws SQLException { break; case XMLA: TestContext.assertEqualsVerbose( - "DATA_SOURCE_NAME=MondrianFoodMart," + "DATA_SOURCE_NAME=FoodMart," + " DATA_SOURCE_DESCRIPTION=Mondrian FoodMart data source," + " URL=http://localhost:8080/mondrian/xmla," - + " DATA_SOURCE_INFO=MondrianFoodMart," + + " DATA_SOURCE_INFO=FoodMart," + + " PROVIDER_NAME=Mondrian," + + " PROVIDER_TYPE=MDP," + + " AUTHENTICATION_MODE=Unauthenticated\n" + + "DATA_SOURCE_NAME=FoodMart2," + + " DATA_SOURCE_DESCRIPTION=Mondrian FoodMart data source," + + " URL=http://localhost:8080/mondrian/xmla," + + " DATA_SOURCE_INFO=FoodMart2," + " PROVIDER_NAME=Mondrian," + " PROVIDER_TYPE=MDP," + " AUTHENTICATION_MODE=Unauthenticated\n", @@ -282,16 +289,18 @@ public void testDatabaseMetaDataGetCatalogs() throws SQLException { olapDatabaseMetaData.getCatalogs(), CATALOGS_COLUMN_NAMES); final String expected; - if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA - || tester.getFlavor() == Tester.Flavor.REMOTE_XMLA) - { + switch (tester.getFlavor()) { + case XMLA: + case REMOTE_XMLA: // XMLA test uses dummy duplicate catalog to make sure that we // get all catalogs expected = "TABLE_CAT=" + catalogName + "\n" + "TABLE_CAT=" + catalogName + "2\n"; - } else { + break; + default: expected = "TABLE_CAT=" + catalogName + "\n"; + break; } TestContext.assertEqualsVerbose(expected, s); } @@ -301,16 +310,18 @@ public void testDatabaseMetaDataGetSchemas() throws SQLException { olapDatabaseMetaData.getSchemas(), SCHEMAS_COLUMN_NAMES); final String expected; - if (tester.getFlavor() == TestContext.Tester.Flavor.XMLA - || tester.getFlavor() == Tester.Flavor.REMOTE_XMLA) - { - // XMLA test uses dummy duplicate catalog to make sure that we - // get all catalogs + switch (tester.getFlavor()) { + case XMLA: + case REMOTE_XMLA: + // XMLA test uses dummy duplicate schema to make sure that we + // get all schemas expected = "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n" + "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "2\n"; - } else { + break; + default: expected = "TABLE_SCHEM=FoodMart, TABLE_CAT=" + catalogName + "\n"; + break; } TestContext.assertEqualsVerbose(expected, s); } diff --git a/testsrc/org/olap4j/MondrianTester.java b/testsrc/org/olap4j/MondrianTester.java deleted file mode 100644 index 0448ea4..0000000 --- a/testsrc/org/olap4j/MondrianTester.java +++ /dev/null @@ -1,73 +0,0 @@ -/* -// 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. -// Copyright (C) 2007-2010 Julian Hyde -// All Rights Reserved. -// You must accept the terms of that agreement to use this software. -*/ -package org.olap4j; - -import org.olap4j.test.TestContext; - -import java.sql.*; -import java.util.Properties; - -/** - * Implementation of {@link org.olap4j.test.TestContext.Tester} which speaks to - * the mondrian olap4j driver. - * - * @author jhyde - * @version $Id$ - */ -public class MondrianTester implements TestContext.Tester { - - public Connection createConnection() throws SQLException { - try { - Class.forName(DRIVER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new RuntimeException("oops", e); - } - return - DriverManager.getConnection( - getURL(), - new Properties()); - } - - public Connection createConnectionWithUserPassword() throws SQLException { - return DriverManager.getConnection( - getURL(), USER, PASSWORD); - } - - public String getDriverUrlPrefix() { - return DRIVER_URL_PREFIX; - } - - public String getDriverClassName() { - return DRIVER_CLASS_NAME; - } - - public String getURL() { - // This property is usually defined in build.properties. See - // examples in that file. - return TestContext.getTestProperties().getProperty( - TestContext.Property.CONNECT_URL.path); - } - - public Flavor getFlavor() { - return Flavor.MONDRIAN; - } - - public TestContext.Wrapper getWrapper() { - return TestContext.Wrapper.NONE; - } - - public static final String DRIVER_CLASS_NAME = - "mondrian.olap4j.MondrianOlap4jDriver"; - - public static final String DRIVER_URL_PREFIX = "jdbc:mondrian:"; - private static final String USER = "sa"; - private static final String PASSWORD = "sa"; -} - -// End MondrianTester.java diff --git a/testsrc/org/olap4j/RemoteXmlaTester.java b/testsrc/org/olap4j/RemoteXmlaTester.java index a92b190..a79f179 100644 --- a/testsrc/org/olap4j/RemoteXmlaTester.java +++ b/testsrc/org/olap4j/RemoteXmlaTester.java @@ -29,12 +29,23 @@ public class RemoteXmlaTester implements Tester { public static final String DRIVER_URL_PREFIX = "jdbc:xmla:"; public static final String DRIVER_CLASS_NAME = "org.olap4j.driver.xmla.XmlaOlap4jDriver"; + private String url = null; private String user = null; private String password = null; + private final TestContext testContext; - public RemoteXmlaTester() { - final Properties properties = TestContext.getTestProperties(); + /** + * Creates a RemoteXmlaTester. + * + *

    The {@link org.olap4j.test.TestContext.Tester} API requires a public + * constructor with a {@link org.olap4j.test.TestContext} parameter. + * + * @param testContext Test context + */ + public RemoteXmlaTester(TestContext testContext) { + this.testContext = testContext; + final Properties properties = testContext.getProperties(); this.url = properties.getProperty( TestContext.Property.REMOTE_XMLA_URL.path); @@ -51,6 +62,10 @@ public RemoteXmlaTester() { TestContext.Property.REMOTE_XMLA_PASSWORD.path); } + public TestContext getTestContext() { + return testContext; + } + public Connection createConnection() throws SQLException { return this.createConnection(url, null, null); } @@ -94,4 +109,4 @@ public Wrapper getWrapper() { return TestContext.Wrapper.NONE; } } -// End RemoteXmlaTester.java \ No newline at end of file +// End RemoteXmlaTester.java diff --git a/testsrc/org/olap4j/XmlaConnectionTest.java b/testsrc/org/olap4j/XmlaConnectionTest.java index 34f33db..6787d77 100644 --- a/testsrc/org/olap4j/XmlaConnectionTest.java +++ b/testsrc/org/olap4j/XmlaConnectionTest.java @@ -215,7 +215,7 @@ public void testNoNonTrivalCallsOnConnect() throws Exception { * @throws Exception If the test fails. */ public void testNoDoubleQuerySubmission() throws Exception { - if (!TestContext.getTestProperties() + if (!TestContext.instance().getProperties() .get(TestContext.Property.HELPER_CLASS_NAME.path) .equals("org.olap4j.XmlaTester")) { diff --git a/testsrc/org/olap4j/XmlaTester.java b/testsrc/org/olap4j/XmlaTester.java index e405ea9..ff673dc 100644 --- a/testsrc/org/olap4j/XmlaTester.java +++ b/testsrc/org/olap4j/XmlaTester.java @@ -25,12 +25,18 @@ * @version $Id$ */ public class XmlaTester implements TestContext.Tester { + private final TestContext testContext; final XmlaOlap4jProxy proxy; final String cookie; private Connection connection; /** - * Creates an XmlaTester + * Creates an XmlaTester. + * + *

    The {@link org.olap4j.test.TestContext.Tester} API requires a public + * constructor with a {@link org.olap4j.test.TestContext} parameter. + * + * @param testContext Test context * * @throws ClassNotFoundException on error * @throws IllegalAccessException on error @@ -38,20 +44,16 @@ public class XmlaTester implements TestContext.Tester { * @throws NoSuchMethodException on error * @throws InvocationTargetException on error */ - public XmlaTester() + public XmlaTester(TestContext testContext) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { - final Properties properties = TestContext.getTestProperties(); + this.testContext = testContext; + final Properties properties = testContext.getProperties(); final String catalogUrl = properties.getProperty( - TestContext.Property.XMLA_CATALOG_URL.path); - if (catalogUrl == null) { - throw new RuntimeException( - "Property " + TestContext.Property.XMLA_CATALOG_URL.path - + " must be specified"); - } + TestContext.Property.XMLA_CATALOG_URL.path, "http://foo"); // Include the same catalog URL twice with different catalog names. This // allows us to detect whether operations are restricting to the current @@ -61,7 +63,8 @@ public XmlaTester() catalogNameUrls.put("FoodMart", catalogUrl); catalogNameUrls.put("FoodMart2", catalogUrl); String urlString = - properties.getProperty(TestContext.Property.CONNECT_URL.path); + properties.getProperty( + TestContext.Property.CONNECT_URL.path, "jdbc:mondrian:"); final Class clazz = Class.forName(getProxyClassName()); final Constructor constructor = @@ -73,6 +76,10 @@ public XmlaTester() XmlaOlap4jDriver.PROXY_MAP.put(cookie, proxy); } + public TestContext getTestContext() { + return testContext; + } + public Connection createConnection() throws SQLException { if (connection != null) { return connection; @@ -114,7 +121,8 @@ public String getDriverClassName() { } public String getURL() { - return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie; + return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + + cookie; } public Flavor getFlavor() { diff --git a/testsrc/org/olap4j/test/TestContext.java b/testsrc/org/olap4j/test/TestContext.java index 362bc80..04861b7 100644 --- a/testsrc/org/olap4j/test/TestContext.java +++ b/testsrc/org/olap4j/test/TestContext.java @@ -10,6 +10,8 @@ package org.olap4j.test; import java.io.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.regex.Pattern; import java.sql.*; @@ -43,7 +45,7 @@ public class TestContext { private static final Pattern LineBreakPattern = Pattern.compile("\r\n|\r|\n"); private static final Pattern TabPattern = Pattern.compile("\t"); - public static Properties testProperties; + private static Properties testProperties; private static final ThreadLocal THREAD_INSTANCE = new ThreadLocal(); @@ -78,16 +80,19 @@ public class TestContext { }; private final Tester tester; + private final Properties properties; /** * Intentionally private: use {@link #instance()}. */ private TestContext() { - tester = createTester(getTestProperties()); + this(getStaticTestProperties()); } - private TestContext(Tester tester) { - this.tester = tester; + private TestContext(Properties properties) { + assert properties != null; + this.properties = properties; + this.tester = createTester(this, properties); } /** @@ -316,25 +321,35 @@ public static String quotePattern(String s) * Factory method for the {@link Tester} * object which determines which driver to test. * + * @param testContext Test context * @param testProperties Properties that define the properties of the tester * @return a new Tester */ - private static Tester createTester(Properties testProperties) { + private static Tester createTester( + TestContext testContext, + Properties testProperties) + { String helperClassName = testProperties.getProperty(Property.HELPER_CLASS_NAME.path); if (helperClassName == null) { - helperClassName = "org.olap4j.MondrianTester"; + helperClassName = "org.olap4j.XmlaTester"; } Tester tester; try { Class clazz = Class.forName(helperClassName); - tester = (Tester) clazz.newInstance(); + final Constructor constructor = + clazz.getConstructor(TestContext.class); + tester = (Tester) constructor.newInstance(testContext); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); } // Apply a wrapper, if the "org.olap4j.test.wrapper" property is @@ -387,7 +402,7 @@ public Wrapper getWrapper() { * @return Test suite that executes the TCK */ public static TestSuite createTckSuite(Properties properties, String name) { - TestContext testContext = new TestContext(createTester(properties)); + TestContext testContext = new TestContext(properties); THREAD_INSTANCE.set(testContext); try { final TestSuite suite = new TestSuite(); @@ -399,6 +414,10 @@ public static TestSuite createTckSuite(Properties properties, String name) { } } + public Properties getProperties() { + return properties; + } + /** * Enumeration of valid values for the * {@link org.olap4j.test.TestContext.Property#WRAPPER} property. @@ -450,7 +469,7 @@ public T unwrap( * @param statement Statement * @param clazz Desired result type * @return Unwrapped object - * @throws SQLException + * @throws SQLException on database error */ public abstract T unwrap( Statement statement, @@ -462,7 +481,7 @@ public abstract T unwrap( * @param connection Connection * @param clazz Desired result type * @return Unwrapped object - * @throws SQLException + * @throws SQLException on database error */ public abstract T unwrap( Connection connection, @@ -480,7 +499,7 @@ public abstract T unwrap( * * @return object containing properties needed by the test suite */ - public static synchronized Properties getTestProperties() { + private static synchronized Properties getStaticTestProperties() { if (testProperties == null) { testProperties = new Properties(System.getProperties()); @@ -563,8 +582,18 @@ public Tester getTester() { * Abstracts the information about specific drivers and database instances * needed by this test. This allows the same test suite to be used for * multiple implementations of olap4j. + * + *

    Must have a public constructor that takes a + * {@link org.olap4j.test.TestContext} as parameter. */ public interface Tester { + /** + * Returns the test context. + * + * @return Test context + */ + TestContext getTestContext(); + /** * Creates a connection * @@ -643,6 +672,10 @@ protected DelegatingTester(Tester tester) { this.tester = tester; } + public TestContext getTestContext() { + return tester.getTestContext(); + } + public Connection createConnection() throws SQLException { return tester.createConnection(); } @@ -683,8 +716,8 @@ public enum Property { /** * Name of the class used by the test infrastructure to make connections * to the olap4j data source and perform other housekeeping operations. - * Valid values include "org.olap4j.MondrianTester" (the default) - * and "org.olap4j.XmlaTester". + * Valid values include "mondrian.test.MondrianOlap4jTester" (the + * default, per test.properties) and "org.olap4j.XmlaTester". */ HELPER_CLASS_NAME("org.olap4j.test.helperClassName"),