From fae7f2f6573e43caf101d0ec3e8bc4f174bf49dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Wed, 28 Dec 2022 08:12:05 +0100 Subject: [PATCH] Add TCK showing using external bundle (h2) and a pax warapped (sqlite) --- .../org/ops4j/pax/jdbc/common/BeanConfig.java | 15 +- .../pax/jdbc/mariadb/impl/Activator.java | 17 +- .../impl/MariaDbDataSourceFactory.java | 5 +- .../oracle/impl/OracleDataSourceFactory.java | 3 + .../ops4j/pax/jdbc/sqlite/impl/Activator.java | 3 +- .../sqlite/impl/SqliteDataSourceFactory.java | 66 +++-- pax-jdbc-tck/pom.xml | 51 ++++ .../org/ops4j/pax/jdbc/tck/JdbcTckTest.java | 41 ++++ .../test/cases/jdbc/junit/JDBCTestCase.java | 231 ++++++++++++++++++ pom.xml | 21 +- 10 files changed, 423 insertions(+), 30 deletions(-) create mode 100644 pax-jdbc-tck/pom.xml create mode 100644 pax-jdbc-tck/src/test/java/org/ops4j/pax/jdbc/tck/JdbcTckTest.java create mode 100644 pax-jdbc-tck/src/test/java/org/osgi/test/cases/jdbc/junit/JDBCTestCase.java diff --git a/pax-jdbc-common/src/main/java/org/ops4j/pax/jdbc/common/BeanConfig.java b/pax-jdbc-common/src/main/java/org/ops4j/pax/jdbc/common/BeanConfig.java index 513d5937..24dc24ab 100644 --- a/pax-jdbc-common/src/main/java/org/ops4j/pax/jdbc/common/BeanConfig.java +++ b/pax-jdbc-common/src/main/java/org/ops4j/pax/jdbc/common/BeanConfig.java @@ -56,11 +56,14 @@ private static Map findSettersForBean(Object bean) { * properties to set. */ public static void configure(Object bean, Properties props) { + configure(bean, props, true); + } + public static void configure(Object bean, Properties props, boolean failOnMissing) { final Map map = new HashMap<>(); for (String key : props.stringPropertyNames()) { map.put(key, props.getProperty(key)); } - BeanConfig.configure(bean, map); + BeanConfig.configure(bean, map, failOnMissing); } /** @@ -72,18 +75,24 @@ public static void configure(Object bean, Properties props) { * properties to set. The keys in the Map have to match the bean property names. */ public static void configure(Object bean, Map props) { + + } + public static void configure(Object bean, Map props, boolean failOnMissing) { BeanConfig beanConfig = new BeanConfig(bean); for (String key : props.keySet()) { - beanConfig.trySetProperty(key, props.get(key)); + beanConfig.trySetProperty(key, props.get(key), failOnMissing); } } - private void trySetProperty(String key, String value) { + private void trySetProperty(String key, String value, boolean failOnMissing) { try { Method method = setters.get(key); if (method == null) { + if (failOnMissing) { throw new IllegalArgumentException("No setter in " + bean.getClass() + " for property " + key); + } + return; } Class paramClass = method.getParameterTypes()[0]; if (paramClass == int.class || paramClass == Integer.class) { diff --git a/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/Activator.java b/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/Activator.java index 738078be..f966830d 100644 --- a/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/Activator.java +++ b/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/Activator.java @@ -28,13 +28,26 @@ public class Activator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { MariaDbDataSourceFactory dsf = new MariaDbDataSourceFactory(); - Dictionary props = new Hashtable(); + Dictionary props = new Hashtable<>(); props.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, Driver.class.getName()); props.put(DataSourceFactory.OSGI_JDBC_DRIVER_NAME, "mariadb"); + props.put(DataSourceFactory.OSGI_JDBC_CAPABILITY, new String[] { + DataSourceFactory.OSGI_JDBC_CAPABILITY_DRIVER, + DataSourceFactory.OSGI_JDBC_CAPABILITY_DATASOURCE, + DataSourceFactory.OSGI_JDBC_CAPABILITY_CONNECTIONPOOLDATASOURCE, + DataSourceFactory.OSGI_JDBC_CAPABILITY_XADATASOURCE + }); context.registerService(DataSourceFactory.class.getName(), dsf, props); - Dictionary props2 = new Hashtable(); + Dictionary props2 = new Hashtable<>(); + //TODO this seems wrong if we want to emulate mysql we should use a different driver class! props2.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, Driver.class.getName()); props2.put(DataSourceFactory.OSGI_JDBC_DRIVER_NAME, "mysql"); + props2.put(DataSourceFactory.OSGI_JDBC_CAPABILITY, new String[] { + DataSourceFactory.OSGI_JDBC_CAPABILITY_DRIVER, + DataSourceFactory.OSGI_JDBC_CAPABILITY_DATASOURCE, + DataSourceFactory.OSGI_JDBC_CAPABILITY_CONNECTIONPOOLDATASOURCE, + DataSourceFactory.OSGI_JDBC_CAPABILITY_XADATASOURCE + }); context.registerService(DataSourceFactory.class.getName(), dsf, props2); } diff --git a/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/MariaDbDataSourceFactory.java b/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/MariaDbDataSourceFactory.java index 8f44ffba..ec80e6fa 100644 --- a/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/MariaDbDataSourceFactory.java +++ b/pax-jdbc-mariadb/src/main/java/org/ops4j/pax/jdbc/mariadb/impl/MariaDbDataSourceFactory.java @@ -37,6 +37,9 @@ public DataSource createDataSource(Properties props) throws SQLException { } private void setProperties(MariaDbDataSource ds, Properties properties) throws SQLException { + if (properties==null) { + return; + } Properties props = (Properties) properties.clone(); String url = (String) props.remove(DataSourceFactory.JDBC_URL); if (url != null) { @@ -66,7 +69,7 @@ private void setProperties(MariaDbDataSource ds, Properties properties) throws S ds.setUser(user); if (!props.isEmpty()) { - BeanConfig.configure(ds, props); + BeanConfig.configure(ds, props, false); } } diff --git a/pax-jdbc-oracle/src/main/java/org/ops4j/pax/jdbc/oracle/impl/OracleDataSourceFactory.java b/pax-jdbc-oracle/src/main/java/org/ops4j/pax/jdbc/oracle/impl/OracleDataSourceFactory.java index 16651074..c435040f 100644 --- a/pax-jdbc-oracle/src/main/java/org/ops4j/pax/jdbc/oracle/impl/OracleDataSourceFactory.java +++ b/pax-jdbc-oracle/src/main/java/org/ops4j/pax/jdbc/oracle/impl/OracleDataSourceFactory.java @@ -75,6 +75,9 @@ public Driver createDriver(Properties props) throws SQLException { private void setProperties(oracle.jdbc.datasource.OracleDataSource ds, Properties properties) throws Exception { + if (properties==null) { + return; + } Properties props = (Properties) properties.clone(); String url = (String) props.remove(DataSourceFactory.JDBC_URL); diff --git a/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/Activator.java b/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/Activator.java index 3bbb3217..62069db5 100644 --- a/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/Activator.java +++ b/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/Activator.java @@ -28,9 +28,10 @@ public class Activator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { SqliteDataSourceFactory dsf = new SqliteDataSourceFactory(); - Dictionary props = new Hashtable(); + Dictionary props = new Hashtable<>(); props.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, JDBC.class.getName()); props.put(DataSourceFactory.OSGI_JDBC_DRIVER_NAME, "sqlite"); + props.put(DataSourceFactory.OSGI_JDBC_CAPABILITY, new String[] {DataSourceFactory.OSGI_JDBC_CAPABILITY_DATASOURCE, DataSourceFactory.OSGI_JDBC_CAPABILITY_DRIVER}); context.registerService(DataSourceFactory.class.getName(), dsf, props); } diff --git a/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/SqliteDataSourceFactory.java b/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/SqliteDataSourceFactory.java index 863c293f..98df3529 100644 --- a/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/SqliteDataSourceFactory.java +++ b/pax-jdbc-sqlite/src/main/java/org/ops4j/pax/jdbc/sqlite/impl/SqliteDataSourceFactory.java @@ -15,6 +15,7 @@ */ package org.ops4j.pax.jdbc.sqlite.impl; +import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; import java.util.Properties; @@ -30,33 +31,60 @@ public class SqliteDataSourceFactory implements DataSourceFactory { - @Override - public DataSource createDataSource(Properties props) throws SQLException { - SQLiteDataSource dataSource = new SQLiteDataSource(); - String url = props.getProperty(JDBC_URL); - if (url == null) { - dataSource.setUrl("jdbc:sqlite:" + props.getProperty(JDBC_DATABASE_NAME)); - props.remove(JDBC_DATABASE_NAME); - } else { - dataSource.setUrl(url); - props.remove(JDBC_URL); - } + private final class SQLiteDataSourceExtension extends SQLiteDataSource { + private String username; + private String password; - if (!props.isEmpty()) { - BeanConfig.configure(dataSource, props); - } - return dataSource; - } + public SQLiteDataSourceExtension(String username, String password) { + this.username = username; + this.password = password; + } - @Override + @Override + public Connection getConnection() throws SQLException { + return super.getConnection(username, password); + } + } + + @Override + public DataSource createDataSource(Properties props) throws SQLException { + String username = removeProperty(props, JDBC_USER); + String password = removeProperty(props, JDBC_PASSWORD); + SQLiteDataSource dataSource = new SQLiteDataSourceExtension(username, password); + if (props != null) { + String url = props.getProperty(JDBC_URL); + if (url == null) { + dataSource.setUrl("jdbc:sqlite:" + props.getProperty(JDBC_DATABASE_NAME)); + props.remove(JDBC_DATABASE_NAME); + } else { + dataSource.setUrl(url); + props.remove(JDBC_URL); + } + if (!props.isEmpty()) { + BeanConfig.configure(dataSource, props, false); + } + } + return dataSource; + } + + private String removeProperty(Properties props, String property) { + if (props != null) { + String value = props.getProperty(property); + props.remove(property); + return value; + } + return null; + } + + @Override public ConnectionPoolDataSource createConnectionPoolDataSource(Properties props) throws SQLException { - throw new UnsupportedOperationException(); + throw new SQLException(); } @Override public XADataSource createXADataSource(Properties props) throws SQLException { - throw new UnsupportedOperationException(); + throw new SQLException(); } @Override diff --git a/pax-jdbc-tck/pom.xml b/pax-jdbc-tck/pom.xml new file mode 100644 index 00000000..72df8d34 --- /dev/null +++ b/pax-jdbc-tck/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + + org.ops4j.pax + jdbc + 1.5.6-SNAPSHOT + + pax-jdbc-tck + OSGi-TCK Tests + + + + com.h2database + h2 + test + + + + org.ops4j.pax.jdbc + pax-jdbc-sqlite + + + org.ops4j.pax.jdbc + pax-jdbc-db2 + + + org.ops4j.pax.jdbc + pax-jdbc-mariadb + + + + org.osgi + org.osgi.test.cases.jdbc + test + + + org.osgi + org.osgi.service.jdbc + test + + + de.laeubisoft + osgi-test-framework + test + + + org.eclipse.platform + org.eclipse.osgi + + + \ No newline at end of file diff --git a/pax-jdbc-tck/src/test/java/org/ops4j/pax/jdbc/tck/JdbcTckTest.java b/pax-jdbc-tck/src/test/java/org/ops4j/pax/jdbc/tck/JdbcTckTest.java new file mode 100644 index 00000000..b6aca7f1 --- /dev/null +++ b/pax-jdbc-tck/src/test/java/org/ops4j/pax/jdbc/tck/JdbcTckTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2022 OPS4J. + * + * 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 org.ops4j.pax.jdbc.tck; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.osgi.test.cases.jdbc.junit.JDBCTestCase; + +import de.laeubisoft.osgi.junit5.framework.annotations.WithBundle; +import de.laeubisoft.osgi.junit5.framework.extension.FrameworkExtension; + +//#### JDBC services to test #### +//some drivers that already have a custom implementation and we just want to include them to make sure they comply +@WithBundle(value = "com.h2database", start = true, isolated = true) +//pax-jdbc-sqlite +@WithBundle(value = "org.ops4j.pax.jdbc.sqlite", start = true, isolated = true) +@WithBundle(value = "org.xerial.sqlite-jdbc", start = true, isolated = true) +//pax-jdbc-mariadb --> actually obsolete see: https://github.com/ops4j/org.ops4j.pax.jdbc/issues/277 +@WithBundle(value = "org.ops4j.pax.jdbc.mariadb", start = true, isolated = true) +@WithBundle(value = "org.mariadb.jdbc", start = true, isolated = true) +//pax-db2 TODO how to test? seems not OpenSource? +// @WithBundle(value = "org.ops4j.pax.jdbc.db2", start = true, isolated = true) + +//### basic setup ### +@ExtendWith(FrameworkExtension.class) +@WithBundle("org.osgi.service.jdbc") +public class JdbcTckTest extends JDBCTestCase { + +} diff --git a/pax-jdbc-tck/src/test/java/org/osgi/test/cases/jdbc/junit/JDBCTestCase.java b/pax-jdbc-tck/src/test/java/org/osgi/test/cases/jdbc/junit/JDBCTestCase.java new file mode 100644 index 00000000..0d60cef5 --- /dev/null +++ b/pax-jdbc-tck/src/test/java/org/osgi/test/cases/jdbc/junit/JDBCTestCase.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + *******************************************************************************/ + +package org.osgi.test.cases.jdbc.junit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_CAPABILITY; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_CAPABILITY_CONNECTIONPOOLDATASOURCE; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_CAPABILITY_DATASOURCE; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_CAPABILITY_DRIVER; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_CAPABILITY_XADATASOURCE; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_CLASS; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_NAME; +import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_VERSION; + +import java.sql.Driver; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.function.Supplier; + +import javax.sql.ConnectionPoolDataSource; +import javax.sql.DataSource; +import javax.sql.XADataSource; + +import org.junit.jupiter.params.ParameterizedTest; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.jdbc.DataSourceFactory; +import org.osgi.test.assertj.servicereference.ServiceReferenceAssert; +import org.osgi.test.common.annotation.InjectBundleContext; +import org.osgi.test.junit5.service.ServiceSource; +// This class is copied from the OSGi repository as long as there is not updated release of the testcase +public class JDBCTestCase { + + static String databaseName = "dbName"; + static String dataSourceName = "dsName"; + static String description = "desc"; + static String password = "pswd"; + static String user = "usr"; + + private static class DfltProps extends Properties { + + private static final long serialVersionUID = 1L; + + DfltProps() { + super(); + put(DataSourceFactory.JDBC_DATABASE_NAME, databaseName); + put(DataSourceFactory.JDBC_DATASOURCE_NAME, dataSourceName); + put(DataSourceFactory.JDBC_DESCRIPTION, description); + put(DataSourceFactory.JDBC_PASSWORD, password); + put(DataSourceFactory.JDBC_USER, user); + // Drivers can support additional custom configuration properties. + } + } + + private static final List> ALL_CAPABILITIES = Arrays.asList( + new JdbcCapability(OSGI_JDBC_CAPABILITY_DRIVER, DataSourceFactory::createDriver, + "org.osgi.service.jdbc.DataSourceFactory.createDriver(Properties)", Properties::new), + new JdbcCapability(OSGI_JDBC_CAPABILITY_DATASOURCE, DataSourceFactory::createDataSource, + "org.osgi.service.jdbc.DataSourceFactory.createDataSource(Properties)", DfltProps::new), + new JdbcCapability(OSGI_JDBC_CAPABILITY_CONNECTIONPOOLDATASOURCE, DataSourceFactory::createConnectionPoolDataSource, + "org.osgi.service.jdbc.DataSourceFactory.createConnectionPoolDataSource(Properties)", DfltProps::new), + new JdbcCapability(OSGI_JDBC_CAPABILITY_XADATASOURCE, DataSourceFactory::createXADataSource, + "org.osgi.service.jdbc.DataSourceFactory.createXADataSource(Properties)", DfltProps::new) + ); + + @InjectBundleContext + BundleContext bundleContext; + + /** + * This test that + *
    + *
  • all required properties are declared and of the required type
  • + *
  • all optional properties are of the required type
  • + *
+ * @param sr the service reference of the {@link DataSourceFactory} + */ + @ParameterizedTest + @ServiceSource(serviceType = DataSourceFactory.class) + public void testRegisteredProperties(ServiceReference sr) { + + ServiceReferenceAssert sRefAssert = ServiceReferenceAssert + .assertThat(sr); + + //first check all mandatory properties + sRefAssert.hasServicePropertiesThat() + .as("According to '125.2 Database Driver' the DataSourceFactory must specify the '%s' with its registration.", + OSGI_JDBC_DRIVER_CLASS) + .containsKey(OSGI_JDBC_DRIVER_CLASS) + .extractingByKey(OSGI_JDBC_DRIVER_CLASS) + .isNotNull() + .as("According to '125.2 Database Driver' the property '%s' must be a String", OSGI_JDBC_DRIVER_CLASS) + .isInstanceOf(String.class); + + sRefAssert.hasServicePropertiesThat() + .as(String.format("According to '125.2 Database Driver' the DataSourceFactory must specify the '%s' with its registration.", + OSGI_JDBC_CAPABILITY)) + .containsKey(OSGI_JDBC_CAPABILITY) + .extractingByKey(OSGI_JDBC_CAPABILITY) + .isNotNull() + .as("According to '125.2 Database Driver' the property '%s' must be a String+", OSGI_JDBC_CAPABILITY) + .isInstanceOfAny(String.class, String[].class, Collection.class); + + //then check optional ones + Object driverVersion = sr.getProperty(OSGI_JDBC_DRIVER_VERSION); + if (driverVersion != null) { + assertThat(driverVersion) + .as("According to '125.2 Database Driver' the property '%s' must be a String if specified", OSGI_JDBC_DRIVER_VERSION) + .isInstanceOf(String.class); + } + Object driverName = sr.getProperty(OSGI_JDBC_DRIVER_NAME); + if (driverName != null) { + assertThat(driverName) + .as("According to '125.2 Database Driver' the property '%s' must be a String if specified", OSGI_JDBC_DRIVER_NAME) + .isInstanceOf(String.class); + } + + } + + /** + * This test that + *
    + *
  • all declared capabilities behave according to their contract
  • + *
  • at least one capability is provided
  • + *
+ * @param sr the service reference of the {@link DataSourceFactory} + */ + @ParameterizedTest + @ServiceSource(serviceType = DataSourceFactory.class) + public void testDeclaredCapabilities(ServiceReference sr) + throws SQLException, InvalidSyntaxException { + boolean providesAny = false; + for (JdbcCapability capability : ALL_CAPABILITIES) { + providesAny |= testCapability(sr, capability); + } + assertThat(providesAny) + .as("According to '125.2 Database Driver' the DataSourceFactory must at laest provide one of the follwoing capabilities '%s'.", ALL_CAPABILITIES) + .isTrue(); + } + + private boolean testCapability(ServiceReference reference, JdbcCapability capability) throws SQLException, InvalidSyntaxException { + DataSourceFactory dsf = bundleContext.getService(reference); + try { + if (bundleContext.createFilter(String.format("(%s=%s)", OSGI_JDBC_CAPABILITY, capability.capability)).match(reference)) { + //if the source declares the support, it should work to create items without an exception + assertThatNoException() + .as("According to '125.2 Database Driver' a DataSourceFactory declaring the capability %s must not throw any exception when invoking %s with a null argument", + capability.capability, capability.functionName) + .isThrownBy(() -> capability.apply(dsf, null)); + assertThat(capability.apply(dsf, null)) + .as("According to '125.2 Database Driver' a DataSourceFactory declaring the capability %s must not return null when invoking %s with a null argument", + capability.capability, capability.functionName) + .isNotNull(); + assertThatNoException() + .as("According to '125.2 Database Driver' a DataSourceFactory declaring the capability %s must not throw any exception when invoking %s with a properties object containing the properties %s", + capability.capability, capability.functionName, capability.standardPropertiesProvider.get()) + .isThrownBy(() -> capability.apply(dsf, capability.standardPropertiesProvider.get())); + assertThat(capability.apply(dsf, capability.standardPropertiesProvider.get())) + .as("According to '125.2 Database Driver' a DataSourceFactory declaring the capability %s must not return null when invoking %s with a properties object containing the properties %s", + capability.capability, capability.functionName, capability.standardPropertiesProvider.get()) + .isNotNull(); + return true; + } else { + //it is required to throw an exception here + assertThatExceptionOfType(SQLException.class) + .as("According to '125.2 Database Driver' a DataSourceFactory not declaring the capability %s must throw SQLException when invoking %s with a null argument", + capability.capability, capability.functionName) + .isThrownBy(() -> capability.apply(dsf, null)); + assertThatExceptionOfType(SQLException.class) + .as("According to '125.2 Database Driver' a DataSourceFactory not declaring the capability %s must throw SQLException when invoking %s a properties object containing the properties %s", + capability.capability, capability.functionName, capability.standardPropertiesProvider.get()) + .isThrownBy(() -> capability.apply(dsf, capability.standardPropertiesProvider.get())); + return false; + } + } finally { + if (dsf != null) { + bundleContext.ungetService(reference); + } + } + } + + private static interface DsfCallback { + R invoke(T t, U u) throws SQLException; + } + + private static final class JdbcCapability { + + private String capability; + private DsfCallback accessorFunction; + private String functionName; + private Supplier standardPropertiesProvider; + + public JdbcCapability(String capability, DsfCallback accessorFunction, String functionName, Supplier standardPropertiesProvider) { + this.capability = capability; + this.accessorFunction = accessorFunction; + this.functionName = functionName; + this.standardPropertiesProvider = standardPropertiesProvider; + } + + @Override + public String toString() { + return capability; + } + + T apply(DataSourceFactory factory, Properties properties) throws SQLException { + return accessorFunction.invoke(factory, properties); + } + + } +} diff --git a/pom.xml b/pom.xml index 9d5cd094..003a1b14 100644 --- a/pom.xml +++ b/pom.xml @@ -179,8 +179,7 @@ 1.9.3_1 1_3 - - 3.12.100 + 3.18.200 7.6.1.Final 3.4.3.Final @@ -196,7 +195,8 @@ 2.6.11 6.0.0 - 1.0.1 + 1.1.0 + 8.1.0 1.7.32 @@ -215,6 +215,7 @@ 2.7.4 42.3.7 3.36.0.3 + 0.0.1 @@ -247,6 +248,7 @@ pax-jdbc-itest pax-jdbc-karaf-itest + pax-jdbc-tck @@ -736,6 +738,12 @@ org.osgi.service.jdbc ${version.org.osgi.service.jdbc} + + org.osgi + org.osgi.test.cases.jdbc + ${version.org.osgi.service.jdbc.tck} + test + org.apache.felix @@ -1035,7 +1043,12 @@ - + + de.laeubisoft + osgi-test-framework + ${version.osgi-test-framework} + test + org.apache.servicemix.bundles org.apache.servicemix.bundles.javax-inject