Skip to content
TestConfigurableServiceConnection.java 71.6 KiB
Newer Older
			ServiceConnection connection = new ConfigurableServiceConnection(geometriesProp);
			assertNotNull(connection.getGeometries());
			assertEquals(4, connection.getGeometries().size());
			assertEquals("POINT", ((ArrayList<String>)connection.getGeometries()).get(0));
			assertEquals("CIRCLE", ((ArrayList<String>)connection.getGeometries()).get(1));
			assertEquals("CONTAINS", ((ArrayList<String>)connection.getGeometries()).get(2));
			assertEquals("INTERSECTS", ((ArrayList<String>)connection.getGeometries()).get(3));
			fail("This MUST have succeeded because the given list of geometries is correct! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" as geometry list:
			ServiceConnection connection = new ConfigurableServiceConnection(noneGeomProp);
			assertNotNull(connection.getGeometries());
			assertEquals(0, connection.getGeometries().size());
			fail("This MUST have succeeded because the given list of geometries is correct (reduced to only NONE)! \nCaught exception: " + getPertinentMessage(e));
		}

		// "ANY" as geometry list:
			ServiceConnection connection = new ConfigurableServiceConnection(anyGeomProp);
			assertNull(connection.getGeometries());
			fail("This MUST have succeeded because the given list of geometries is correct (reduced to only ANY)! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" inside a geometry list:
			new ConfigurableServiceConnection(noneInsideGeomProp);
			fail("This MUST have failed because the given geometry list contains at least 2 items, whose one is NONE!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("The special value \"" + VALUE_NONE + "\" can not be used inside a list! It MUST be used in replacement of a whole list to specify that no value is allowed.", e.getMessage());
			new ConfigurableServiceConnection(unknownGeomProp);
			fail("This MUST have failed because the given geometry list contains at least 1 unknown ADQL geometrical function!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Unknown ADQL geometrical function: \"foo\"!", e.getMessage());
		}

			ServiceConnection connection = new ConfigurableServiceConnection(coordSysProp);
			assertNotNull(connection.getCoordinateSystems());
			assertEquals(2, connection.getCoordinateSystems().size());
			assertEquals("icrs *		*", ((ArrayList<String>)connection.getCoordinateSystems()).get(0));
			assertEquals("ICrs * (Spherical2|  	CARTEsian2)", ((ArrayList<String>)connection.getCoordinateSystems()).get(1));
			fail("This MUST have succeeded because the given list of coordinate systems is correct! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" as coordinate systems list:
			ServiceConnection connection = new ConfigurableServiceConnection(noneCoordSysProp);
			assertNotNull(connection.getCoordinateSystems());
			assertEquals(0, connection.getCoordinateSystems().size());
			fail("This MUST have succeeded because the given list of coordinate systems is correct (reduced to only NONE)! \nCaught exception: " + getPertinentMessage(e));
		}

		// "ANY" as coordinate systems list:
			ServiceConnection connection = new ConfigurableServiceConnection(anyCoordSysProp);
			assertNull(connection.getCoordinateSystems());
			fail("This MUST have succeeded because the given list of coordinate systems is correct (reduced to only ANY)! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" inside a coordinate systems list:
			new ConfigurableServiceConnection(noneInsideCoordSysProp);
			fail("This MUST have failed because the given coordinate systems list contains at least 3 items, whose one is NONE!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("The special value \"" + VALUE_NONE + "\" can not be used inside a list! It MUST be used in replacement of a whole list to specify that no value is allowed.", e.getMessage());
		}

		// Unknown coordinate system function:
			new ConfigurableServiceConnection(unknownCoordSysProp);
			fail("This MUST have failed because the given coordinate systems list contains at least 1 unknown coordinate system!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Incorrect coordinate system regular expression (\"ICRS foo *\"): Wrong allowed coordinate system syntax for the 1-th item: \"ICRS foo *\"! Expected: \"frameRegExp refposRegExp flavorRegExp\" ; where each xxxRegExp = (xxx | '*' | '('xxx ('|' xxx)*')'), frame=\"" + Frame.regexp + "\", refpos=\"" + RefPos.regexp + "\" and flavor=\"" + Flavor.regexp + "\" ; an empty string is also allowed and will be interpreted as '*' (so all possible values).", e.getMessage());
		}

		// "ANY" as UDFs list:
			ServiceConnection connection = new ConfigurableServiceConnection(anyUdfsProp);
			assertNull(connection.getUDFs());
			fail("This MUST have succeeded because the given list of UDFs is correct (reduced to only ANY)! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" as UDFs list:
			ServiceConnection connection = new ConfigurableServiceConnection(noneUdfsProp);
			assertNotNull(connection.getUDFs());
			assertEquals(0, connection.getUDFs().size());
			fail("This MUST have succeeded because the given list of UDFs is correct (reduced to only NONE)! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid list of UDFs:
			ServiceConnection connection = new ConfigurableServiceConnection(udfsProp);
			assertNotNull(connection.getUDFs());
			assertEquals(2, connection.getUDFs().size());
			Iterator<FunctionDef> it = connection.getUDFs().iterator();
			assertEquals("toto(a VARCHAR)", it.next().toString());
			assertEquals("titi(b REAL) -> DOUBLE", it.next().toString());
		} catch(Exception e) {
			fail("This MUST have succeeded because the given list of UDFs contains valid items! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid list of UDFs containing UDFs with translation pattern:
		try {
			ServiceConnection connection = new ConfigurableServiceConnection(udfsWithTranslationProp);
			assertNotNull(connection.getUDFs());
			assertEquals(2, connection.getUDFs().size());
			Iterator<FunctionDef> it = connection.getUDFs().iterator();
			FunctionDef def = it.next();
			assertEquals("lower(a VARCHAR) -> VARCHAR", def.toString());
			assertEquals("toLowerCase($1)", def.getTranslationPattern());
			assertNull(def.description);
			def = it.next();
			assertEquals("substring(str VARCHAR, sub VARCHAR, startIndex INTEGER) -> VARCHAR", def.toString());
			assertEquals("substr($1, $2, $3)", def.getTranslationPattern());
			assertEquals("Extract a substring.", def.description);
		} catch(Exception e) {
			fail("This MUST have succeeded because the given list of UDFs contains valid items! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid list of UDFs containing one UDF with a class name:
			ServiceConnection connection = new ConfigurableServiceConnection(udfsWithClassNameProp);
			assertNotNull(connection.getUDFs());
			assertEquals(1, connection.getUDFs().size());
			FunctionDef def = connection.getUDFs().iterator().next();
			assertEquals("toto(a VARCHAR) -> VARCHAR", def.toString());
			assertEquals(UDFToto.class, def.getUDFClass());
			fail("This MUST have succeeded because the given list of UDFs contains valid items! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid list of UDFs containing one UDF with a class name AND a description:
			ServiceConnection connection = new ConfigurableServiceConnection(udfsWithClassNameAndDescriptionProp);
			assertNotNull(connection.getUDFs());
			assertEquals(2, connection.getUDFs().size());
			Iterator<FunctionDef> itUdfs = connection.getUDFs().iterator();
			FunctionDef def = itUdfs.next();
			assertEquals("toto(a VARCHAR) -> VARCHAR", def.toString());
			assertEquals(UDFToto.class, def.getUDFClass());
			assertEquals("Bla \\\"bla\\\".", def.description);
			def = itUdfs.next();
			assertEquals("titi(b REAL) -> DOUBLE", def.toString());
			assertEquals(UDFToto.class, def.getUDFClass());
			assertEquals("Function titi.", def.description);
			e.printStackTrace();
			fail("This MUST have succeeded because the given list of UDFs contains valid items! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid list of UDFs containing one UDF with empty optional parameters:
			ServiceConnection connection = new ConfigurableServiceConnection(udfsWithEmptyOptParamsProp);
			assertNotNull(connection.getUDFs());
			assertEquals(1, connection.getUDFs().size());
			FunctionDef def = connection.getUDFs().iterator().next();
			assertEquals("toto(a VARCHAR) -> VARCHAR", def.toString());
			assertNull(def.getUDFClass());
			assertNull(def.description);
			fail("This MUST have succeeded because the given list of UDFs contains valid items! \nCaught exception: " + getPertinentMessage(e));
		}

		// "NONE" inside a UDFs list:
			new ConfigurableServiceConnection(udfsListWithNONEorANYProp);
			fail("This MUST have failed because the given UDFs list contains at least 2 items, whose one is ANY!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: \"ANY\"! (position in the property " + KEY_UDFS + ": 27-30)", e.getMessage());
			new ConfigurableServiceConnection(udfsWithMissingBracketsProp);
			fail("This MUST have failed because one UDFs list item has no brackets!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: \"toto(a string)->VARCHAR\"! (position in the property " + KEY_UDFS + ": 1-24)", e.getMessage());
		}

		// UDF with a badly formatted description:
			new ConfigurableServiceConnection(udfsWithWrongDescriptionFormatProp);
			fail("This MUST have failed because one UDFs list item has too many parameters!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: \"[toto(a string)->VARCHAR, {adql.db.TestDBChecker$UDFToto}, Blabla]\"! (position in the property " + KEY_UDFS + ": 1-67)", e.getMessage());
		}

		// UDFs whose one item have more parts than supported:
			new ConfigurableServiceConnection(udfsWithWrongParamLengthProp);
			fail("This MUST have failed because one UDFs list item has too many parameters!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: \"[toto(a string)->VARCHAR, {adql.db.TestDBChecker$UDFToto}, \"Blabla\", foo]\"! (position in the property " + KEY_UDFS + ": 1-74)", e.getMessage());
		}

		// UDF with missing definition part (or wrong since there is no comma):
			new ConfigurableServiceConnection(udfsWithMissingDefProp1);
			fail("This MUST have failed because one UDFs list item has a wrong signature part (it has been forgotten)!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: Wrong function definition syntax! Expected syntax: \"<regular_identifier>(<parameters>?) <return_type>?\", where <regular_identifier>=\"[a-zA-Z]+[a-zA-Z0-9_]*\", <return_type>=\" -> <type_name>\", <parameters>=\"(<regular_identifier> <type_name> (, <regular_identifier> <type_name>)*)\", <type_name> should be one of the types described in the UPLOAD section of the TAP documentation. Examples of good syntax: \"foo()\", \"foo() -> VARCHAR\", \"foo(param INTEGER)\", \"foo(param1 INTEGER, param2 DOUBLE) -> DOUBLE\" (position in the property " + KEY_UDFS + ": 2-33)", e.getMessage());
		}

		// UDF with missing definition part (or wrong since there is no comma):
			new ConfigurableServiceConnection(udfsWithMissingDefProp2);
			fail("This MUST have failed because one UDFs list item has no signature part!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Missing UDF declaration! (position in the property " + KEY_UDFS + ": 2-2)", e.getMessage());
		}

		// Empty UDF item (without comma):
			ServiceConnection connection = new ConfigurableServiceConnection(emptyUdfItemProp1);
			assertNotNull(connection.getUDFs());
			assertEquals(0, connection.getUDFs().size());
			fail("This MUST have succeeded because the given list of UDFs contains one empty UDF (which should be merely ignored)! \nCaught exception: " + getPertinentMessage(e));
		}

		// Empty UDF item (with comma):
			ServiceConnection connection = new ConfigurableServiceConnection(emptyUdfItemProp2);
			assertNotNull(connection.getUDFs());
			assertEquals(0, connection.getUDFs().size());
			fail("This MUST have succeeded because the given list of UDFs contains one empty UDF (which should be merely ignored)! \nCaught exception: " + getPertinentMessage(e));
		}

		// UDF item without its closing bracket:
			new ConfigurableServiceConnection(udfWithMissingEndBracketProp);
			fail("This MUST have failed because one UDFs list item has no closing bracket!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Wrong UDF declaration syntax: \"[toto(a string)->VARCHAR\"! (position in the property " + KEY_UDFS + ": 1-25)", e.getMessage());
			ServiceConnection connection = new ConfigurableServiceConnection(customFactoryProp);
			assertNotNull(connection.getFactory());
			assertEquals(CustomTAPFactory.class, connection.getFactory().getClass());
			fail("This MUST have succeeded because the given custom TAPFactory exists and have the required constructor (ServiceConnection)! \nCaught exception: " + getPertinentMessage(e));
		}

		// Valid custom "configurable" TAPFactory:
			ServiceConnection connection = new ConfigurableServiceConnection(customConfigurableFactoryProp);
			assertNotNull(connection.getFactory());
			assertEquals(CustomConfigurableTAPFactory.class, connection.getFactory().getClass());
			fail("This MUST have succeeded because the given custom configurable TAPFactory exists and have the required constructor (ServiceConnection, Properties)! \nCaught exception: " + getPertinentMessage(e));
		}

		// Bad custom TAPFactory (required constructor missing):
			new ConfigurableServiceConnection(badCustomFactoryProp);
			fail("This MUST have failed because the specified TAPFactory extension does not have a constructor with ServiceConnection!");
			assertEquals(TAPException.class, e.getClass());
			assertEquals("Missing constructor tap.config.TestConfigurableServiceConnection$BadCustomTAPFactory(tap.ServiceConnection)! See the value \"{tap.config.TestConfigurableServiceConnection$BadCustomTAPFactory}\" of the property \"" + KEY_TAP_FACTORY + "\".", e.getMessage());
		}
		final String rootPath = "/ROOT", propertyName = "SuperProperty";
		String path;

			// NULL test => NULL must be returned.
			assertNull(ConfigurableServiceConnection.getFile(null, rootPath, propertyName));

			// Valid absolute file path:
			path = "/custom/user/dir";
			assertEquals(path, ConfigurableServiceConnection.getFile(path, rootPath, propertyName).getAbsolutePath());

			// File name relative to the given rootPath:
			path = "dir";
			assertEquals(rootPath + File.separator + path, ConfigurableServiceConnection.getFile(path, rootPath, propertyName).getAbsolutePath());

			// Idem but with a relative file path:
			path = "gmantele/workspace";
			assertEquals(rootPath + File.separator + path, ConfigurableServiceConnection.getFile(path, rootPath, propertyName).getAbsolutePath());

			ex.printStackTrace();
			fail("None of these tests should have failed!");
		}

		// Test with a file URI:
		path = "file:/custom/user/dir";
			ConfigurableServiceConnection.getFile(path, rootPath, propertyName);
			fail("This test should have failed, because URIs are no longer supported!");
			assertEquals(TAPException.class, ex.getClass());
			assertEquals("Incorrect file path for the property \"" + propertyName + "\": \"" + path + "\"! URI/URLs are not expected here.", ex.getMessage());
		}

		// Test with an URL:
		path = "http://www.google.com";
			ConfigurableServiceConnection.getFile(path, rootPath, propertyName);
			fail("This test should have failed, because the given URI uses the HTTP protocol (actually, it uses a protocol different from \"file\"!");
			assertEquals(TAPException.class, ex.getClass());
			assertEquals("Incorrect file path for the property \"" + propertyName + "\": \"" + path + "\"! URI/URLs are not expected here.", ex.getMessage());
	public static final String getPertinentMessage(final Exception ex) {
		return (ex.getCause() == null || ex.getMessage().equals(ex.getCause().getMessage())) ? ex.getMessage() : ex.getCause().getMessage();
	}

	/**
	 * A UWSFileManager to test the load of a UWSFileManager from the configuration file with a class path.
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @see TestConfigurableServiceConnection#testDefaultServiceConnectionProperties()
	public static class FileManagerTest extends LocalUWSFileManager {
		public FileManagerTest(Properties tapConfig) throws UWSException {
			super(new File(tapConfig.getProperty("file_root_path")), true, false);
		}
	}

	/**
	 * A UserIdentifier which always return the same user...that's to say, all users are in a way still anonymous :-)
	 * This class is only for test purpose.
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 02/2015
	 */
	public static class UserIdentifierTest implements UserIdentifier {
		private static final long serialVersionUID = 1L;

		private final JobOwner everybody = new DefaultJobOwner("everybody");

		@Override
		public JobOwner extractUserId(UWSUrl urlInterpreter, HttpServletRequest request) throws UWSException {
		public JobOwner restoreUser(String id, String pseudo, Map<String, Object> otherData) throws UWSException {
	/**
	 * TAPFactory just to test whether the property tap_factory works well.
	 * @author Gr&eacute;gory Mantelet (ARI)
	 */
	private static class CustomTAPFactory extends AbstractTAPFactory {

		private final JDBCConnection dbConn;

		public CustomTAPFactory(final ServiceConnection conn) throws DBException {
			dbConn = new JDBCConnection(DBTools.DB_TEST_JDBC_DRIVER, DBTools.DB_TEST_URL, DBTools.DB_TEST_USER, DBTools.DB_TEST_PWD, new AstroH2Translator(), "TheOnlyConnection", new QueryExecutor(), conn.getLogger());
		public DBConnection getConnection(final String jobID) throws TAPException {
		public void freeConnection(final DBConnection conn) {
	/**
	 * ConfigurableTAPFactory just to test whether the property tap_factory allows TAPFactory
	 * with a constructor (ServiceConnection, Properties).
	 * @author Gr&eacute;gory Mantelet (ARI)
	 */
	private static class CustomConfigurableTAPFactory extends AbstractTAPFactory {

		private final JDBCConnection dbConn;

		public CustomConfigurableTAPFactory(final ServiceConnection conn, final Properties prop) throws DBException {
			dbConn = new JDBCConnection(DBTools.DB_TEST_JDBC_DRIVER, DBTools.DB_TEST_URL, DBTools.DB_TEST_USER, DBTools.DB_TEST_PWD, new AstroH2Translator(), "TheOnlyConnection", new QueryExecutor(), conn.getLogger());
		public DBConnection getConnection(final String jobID) throws TAPException {
		public void freeConnection(final DBConnection conn) {
	/**
	 * TAPFactory just to test whether the property tap_factory is rejected when no constructor with a single parameter of type ServiceConnection exists.
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 02/2015
	 */
	private static class BadCustomTAPFactory extends AbstractTAPFactory {

		public BadCustomTAPFactory() throws DBException {
		public DBConnection getConnection(final String jobID) throws TAPException {
		public void freeConnection(final DBConnection conn) {
	/**
	 * TAPMetadata extension just to test whether it is possible to customize the output class of ConfigurableServiceConnection with the
	 * metadata fetching methods "db" and "xml".
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 08/2015
	 */
	private static class MyCustomTAPMetadata extends TAPMetadata {
		public MyCustomTAPMetadata(TAPMetadata meta) {
			for(TAPSchema s : meta) {
				this.addSchema(s);
			}
		}
	}

	/**
	 * TAPMetadata extension just to test whether it is possible to customize the output class of ConfigurableServiceConnection with the
	 * metadata fetching methods "db" and "xml".
	 * <strong>This extension is however bad because it does not have any of the required constructor.</strong>
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 08/2015
	 */
	private static class MyBadCustomTAPMetadata extends TAPMetadata {
	 * <p><i>
	 * 	Actually, for quick implementation, this class just extends
	 * 	{@link DefaultTAPLog} (and so, implements TAPLog).
	 * </i></p>
	 * @author Gr&eacute;gory Mantelet (ARI)
	 * @version 09/2017
	 */
	private static class CustomLogger extends DefaultTAPLog {
		public CustomLogger(final UWSFileManager fm) {
		public void logTAP(LogLevel level, Object obj, String event, String message, Throwable error) {
			super.logTAP(level, obj, event, "[MY] " + message, error);
		}

	}