/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.olingo; import static org.junit.Assert.*; import java.io.FileInputStream; import java.io.IOException; import java.math.BigDecimal; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.TimeZone; import javax.servlet.DispatcherType; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.core.Encoder; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.infinispan.transaction.tm.DummyBaseTransactionManager; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.teiid.GeneratedKeys; import org.teiid.adminapi.Admin.SchemaObjectType; import org.teiid.adminapi.Model; import org.teiid.adminapi.impl.ModelMetaData; import org.teiid.core.TeiidRuntimeException; import org.teiid.core.util.ObjectConverterUtil; import org.teiid.core.util.TimestampWithTimezone; import org.teiid.core.util.UnitTestUtil; import org.teiid.deployers.VirtualDatabaseException; import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository.ConnectorManagerException; import org.teiid.dqp.service.AutoGenDataService; import org.teiid.jdbc.ConnectionImpl; import org.teiid.jdbc.TeiidDriver; import org.teiid.language.QueryExpression; import org.teiid.metadata.KeyRecord; import org.teiid.metadata.MetadataStore; import org.teiid.metadata.RuntimeMetadata; import org.teiid.metadata.Schema; import org.teiid.metadata.Table; import org.teiid.odata.api.Client; import org.teiid.odata.api.SQLParameter; import org.teiid.odata.api.UpdateResponse; import org.teiid.olingo.service.LocalClient; import org.teiid.olingo.web.ODataFilter; import org.teiid.olingo.web.ODataServlet; import org.teiid.query.metadata.DDLStringVisitor; import org.teiid.query.sql.lang.Command; import org.teiid.query.sql.symbol.ElementSymbol; import org.teiid.query.sql.symbol.Expression; import org.teiid.query.unittest.RealMetadataFactory; import org.teiid.query.unittest.TimestampUtil; import org.teiid.runtime.EmbeddedConfiguration; import org.teiid.runtime.EmbeddedServer; import org.teiid.runtime.HardCodedExecutionFactory; import org.teiid.translator.DataNotAvailableException; import org.teiid.translator.ExecutionContext; import org.teiid.translator.ResultSetExecution; import org.teiid.translator.TranslatorException; import org.teiid.translator.UpdateExecution; import org.teiid.translator.loopback.LoopbackExecutionFactory; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @SuppressWarnings("nls") public class TestODataIntegration { private static final class UnitTestLocalClient extends LocalClient { private final Properties properties; private final TeiidDriver driver; private final String vdb; ConnectionImpl conn; private boolean throwUpdateException; private boolean rollback; private UnitTestLocalClient(String vdbName, String vdbVersion, Properties properties, Properties properties2, TeiidDriver driver, String vdb) { super(vdbName, vdbVersion, properties); this.properties = properties2; this.driver = driver; this.vdb = vdb; } @Override public ConnectionImpl getConnection() { return conn; } @Override public void close() throws SQLException { if (conn != null) { conn.close(); } } @Override public Connection open() throws SQLException { try { conn = LocalClient.buildConnection(driver, vdb, "1", properties); return conn; } catch (SQLException e) { e.printStackTrace(); } return null; } @Override public UpdateResponse executeUpdate(Command query, List<SQLParameter> parameters) throws SQLException { if (throwUpdateException) { throw new TeiidRuntimeException(); } return super.executeUpdate(query, parameters); } public void setThrowUpdateException(boolean throwUpdateException) { this.throwUpdateException = throwUpdateException; } @Override public void rollback(String txnId) throws SQLException { rollback = true; super.rollback(txnId); } public boolean isRollback() { return rollback; } } private static final String CRLF = "\r\n"; private static final String MIME_HEADERS = "Content-Type: application/http" + CRLF + "Content-Transfer-Encoding: binary" + CRLF; private static EmbeddedServer teiid; private static Server server = new Server(); private static String baseURL; private static HttpClient http = new HttpClient(); private static UnitTestLocalClient localClient; private LoopbackExecutionFactory ef; @Before public void before() throws Exception { TimestampWithTimezone.resetCalendar(TimeZone.getTimeZone("UTC")); teiid = new EmbeddedServer(); EmbeddedConfiguration config = new EmbeddedConfiguration(); config.setTransactionManager(new DummyBaseTransactionManager()); teiid.start(config); ef = new LoopbackExecutionFactory() { @Override public boolean supportsRowOffset() { return false; } }; teiid.addTranslator("loopback", ef); createContext("/odata4", null); deployVDB(); } private void createContext(String contextPath, Map<String, String> properties) throws Exception { ServerConnector connector = new ServerConnector(server); server.setConnectors(new Connector[] { connector }); ServletContextHandler context = new ServletContextHandler(); if (properties != null) { for (Map.Entry<String, String> prop : properties.entrySet()) { context.setInitParameter(prop.getKey(), prop.getValue()); } } context.setContextPath(contextPath); context.addServlet(new ServletHolder(new ODataServlet()), "/*"); context.addFilter(new FilterHolder(new ODataFilter() { @Override public Client buildClient(String vdbName, String version, Properties props) { if (localClient != null) { return localClient; } return getClient(teiid.getDriver(), vdbName, props); } }), "/*", EnumSet.allOf(DispatcherType.class)); server.setHandler(context); server.start(); int port = connector.getLocalPort(); http.start(); baseURL = "http://localhost:"+port+contextPath; } @After public void after() throws Exception { http.stop(); TimestampWithTimezone.resetCalendar(null); server.stop(); teiid.stop(); } private static void deployVDB() throws IOException, ConnectorManagerException, VirtualDatabaseException, TranslatorException { teiid.deployVDB(new FileInputStream(UnitTestUtil.getTestDataFile("loopy-vdb.xml"))); } private JsonNode getJSONNode(ContentResponse response) throws IOException, JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode node = objectMapper.readTree(response.getContent()); return node; } @Test public void testMetadata() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/$metadata"); assertEquals(200, response.getStatus()); assertEquals(ObjectConverterUtil.convertFileToString( UnitTestUtil.getTestDataFile("loopy-edmx-metadata.xml")).replace("${baseurl}", baseURL), response.getContentAsString()); } @Test public void testSystemMetadata() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/SYS/$metadata"); assertEquals(200, response.getStatus()); } @Test public void testServiceMetadata() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/VM1"); assertEquals(200, response.getStatus()); String expected = "{" + "\"@odata.context\":\""+baseURL+"/loopy/VM1/$metadata\"," + "\"value\":[{" + "\"name\":\"G1\"," + "\"url\":\"G1\"" + "},{" + "\"name\":\"G2\"," + "\"url\":\"G2\"" + "},{" + "\"name\":\"G4\"," + "\"url\":\"G4\"" + "},{\"name\":\"LobTable\",\"url\":\"LobTable\"}]" + "}"; assertEquals(expected, response.getContentAsString()); } @Test public void testFilterExpression() throws Exception { //won't resolve ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1?$filter=e1"); assertEquals(400, response.getStatus()); response = http.GET(baseURL + "/loopy/vm1/G1?$filter=true"); assertEquals(200, response.getStatus()); } @Test public void testEntitySet() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1\",\"value\":[{\"e1\":\"ABCDEFGHIJ\",\"e2\":0,\"e3\":0.0}]}", response.getContentAsString()); } @Test public void testEntitySetSkipOnly() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1?$skip=1"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1\",\"value\":[]}", response.getContentAsString()); } @Test public void testEntitySetWithKey() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1/$entity\",\"e1\":\"ABCDEFGHIJ\",\"e2\":0,\"e3\":0.0}", response.getContentAsString()); } @Test public void testIndividualProperty() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)/e1"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1(0)/e1\",\"value\":\"ABCDEFGHIJ\"}", response.getContentAsString()); } @Test public void testEntity() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1/$entity\",\"e1\":\"ABCDEFGHIJ\",\"e2\":0,\"e3\":0.0}", response.getContentAsString()); } @Test public void testIndividualProperty$Value() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)/e1/$value"); assertEquals(200, response.getStatus()); assertEquals("ABCDEFGHIJ",response.getContentAsString()); } @Test public void testIndividualProperty$ValueNoRow() throws Exception { ef.setRowCount(0); ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)/e1/$value"); assertEquals(404, response.getStatus()); } @Test public void testNavigation_1_to_1() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/pm1/G2(0)/FK0"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G1/$entity\",\"e1\":\"ABCDEFGHIJ\",\"e2\":0,\"e3\":0.0}", response.getContentAsString()); } @Test public void testNavigation_1_to_many() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/G1(0)/G2_FK0"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#G2\",\"value\":[{\"e1\":\"ABCDEFGHIJ\",\"e2\":0}]}", response.getContentAsString()); } @Test public void testInsert() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("INSERT INTO x (a, b) VALUES ('teiid', 'dv')", new int[] {1}); teiid.addTranslator("x10", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);"); mmd.addSourceMapping("x10", "x10", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); String payload = "{\n" + " \"a\":\"teiid\",\n" + " \"b\":\"dv\"\n" + "}"; ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider(payload)) .header("Content-Type", "application/json") .header("Prefer", "return=minimal") .send(); assertEquals(204, response.getStatus()); assertTrue(response.getHeaders().get("OData-EntityId").endsWith("northwind/m/x('ABCDEFG')")); //assertEquals("ABCDEFGHIJ",response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testInsertDifferentTypes() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory() { @Override public boolean supportsCompareCriteriaEquals() { return true; } @Override public UpdateExecution createUpdateExecution( org.teiid.language.Command command, ExecutionContext executionContext, RuntimeMetadata metadata, Object connection) throws TranslatorException { addUpdate(command.toString(), new int[] {1}); return super.createUpdateExecution(command, executionContext, metadata,connection); } }; hc.addUpdate("INSERT INTO PostTable (intkey, intnum, stringkey, stringval, booleanval, " + "decimalval, timeval, dateval, timestampval) " + "VALUES (4, 4, '4', 'value_4', FALSE, -20.4, {t '00:00:04'}, " + "{d '2004-04-04'}, {ts '2004-01-01 00:00:04.0'})", new int[] {1}); hc.addData("SELECT PostTable.intkey, PostTable.intnum, PostTable.stringkey, " + "PostTable.stringval, PostTable.booleanval, PostTable.decimalval, " + "PostTable.timeval, PostTable.dateval, PostTable.timestampval, " + "PostTable.clobval FROM PostTable " + "WHERE PostTable.intkey = 4", Arrays.asList(Arrays.asList(4, 4, "4", "value_4", false, new BigDecimal("-20.4"), new java.sql.Time(0), new java.sql.Date(0), new java.sql.Timestamp(0), null))); teiid.addTranslator("x11", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "CREATE foreign TABLE PostTable(\n" + "intkey integer PRIMARY KEY,\n" + "intnum integer,\n" + "stringkey varchar(20),\n" + "stringval varchar(20),\n" + "booleanval boolean,\n" + " decimalval decimal(20, 10),\n" + "timeval time,\n" + "dateval date,\n" + "timestampval timestamp,\n" + "clobval clob) options (updatable true);"); mmd.addSourceMapping("x11", "x11", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); String payload = "\n" + "<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" " + "xmlns:georss=\"http://www.georss.org/georss\" " + "xmlns:gml=\"http://www.opengis.net/gml\" " + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\">\n" + " <category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\" />\n" + " <content type=\"application/xml\">\n" + " <m:properties>\n" + " <d:intkey m:type=\"Int32\">4</d:intkey>\n" + " <d:intnum m:type=\"Int32\">4</d:intnum>\n" + " <d:stringkey>4</d:stringkey>\n" + " <d:stringval>value_4</d:stringval>\n" + " <d:booleanval m:type=\"Boolean\">false</d:booleanval>\n" + " <d:decimalval m:type=\"Double\">-20.4</d:decimalval>\n" + " <d:timeval m:type=\"TimeOfDay\">00:00:04</d:timeval>\n" + " <d:dateval m:type=\"Date\">2004-04-04</d:dateval>\n" + " <d:timestampval m:type=\"DateTimeOffset\">2004-01-01T00:00:04Z</d:timestampval>\n" + " </m:properties>\n" + " </content>\n" + "</entry>"; ContentResponse response = http.newRequest(baseURL + "/northwind/m/PostTable") .method("POST") .content(new StringContentProvider(payload)) .header("Content-Type", "application/xml") .header("Prefer", "return=minimal") .send(); assertEquals(204, response.getStatus()); assertTrue(response.getHeaders().get("OData-EntityId"), response.getHeaders().get("OData-EntityId").endsWith("northwind/m/PostTable(4)")); String jsonPlayload= "{\n" + " \"intkey\":4,\n" + " \"intnum\":4,\n" + " \"stringkey\":\"4\",\n" + " \"stringval\":\"value_4\",\n" + " \"booleanval\":false,\n" + " \"decimalval\":-20.4,\n" + " \"timeval\":\"00:00:04\",\n" + " \"dateval\":\"2004-04-04\",\n" + " \"timestampval\":\"2004-01-01T00:00:04Z\"" + "}"; response = http.newRequest(baseURL + "/northwind/m/PostTable") .method("POST") .content(new StringContentProvider(jsonPlayload)) .header("Content-Type", "application/json") .header("Prefer", "return=representation") .send(); assertEquals(201, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#PostTable\"," + "\"intkey\":4," + "\"intnum\":4," + "\"stringkey\":\"4\"," + "\"stringval\":\"value_4\"," + "\"booleanval\":false," + "\"decimalval\":-20.4," + "\"timeval\":\"00:00:00\"," + "\"dateval\":\"1970-01-01\"," + "\"timestampval\":\"1970-01-01T00:00:00Z\"" + "}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/PostTable(4)/clobval") .method("POST") .content(new StringContentProvider("clob value")) .send(); assertEquals(405, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/PostTable(4)/clobval") .method("PUT") .content(new StringContentProvider("clob value")) .send(); assertEquals(204, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/PostTable(4)/clobval") .method("DELETE") .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testDeepInsert() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addUpdate("INSERT INTO x (a, b) VALUES ('teiid', 'dv')", new int[] {1}); hc.addUpdate("INSERT INTO y (a, b) VALUES ('odata', 'teiid')", new int[] {1}); hc.addUpdate("INSERT INTO y (a, b) VALUES ('odata4', 'teiid')", new int[] {1}); hc.addUpdate("INSERT INTO z (a, b) VALUES ('odata', 'teiid')", new int[] {1}); hc.addUpdate("INSERT INTO z (a, b) VALUES ('odata4', 'olingo4')", new int[] {1}); hc.addData("SELECT x.a, x.b FROM x", Arrays.asList(Arrays.asList("teiid", "dv"))); hc.addData("SELECT y.b, y.a FROM y", Arrays.asList(Arrays.asList("teiid", "odata"), Arrays.asList("teiid", "odata4"))); hc.addData("SELECT z.b, z.a FROM z", Arrays.asList(Arrays.asList("teiid", "odata"), Arrays.asList("olingo4", "odata4"))); teiid.addTranslator("x10", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);" + "create foreign table z (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);"); mmd.addSourceMapping("x10", "x10", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); // update to collection based reference String payload = "{\n" + " \"a\":\"teiid\",\n" + " \"b\":\"dv\",\n" + " \"y_FKX\": [\n"+ " {"+ " \"a\":\"odata\",\n" + " \"b\":\"teiid\"\n" + " },\n"+ " {\n"+ " \"a\":\"odata4\",\n" + " \"b\":\"teiid\"\n" + " }\n"+ " ]\n"+ "}"; ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider(payload), ContentType.APPLICATION_JSON.toString()) // when this header is defined the return should be expanded, but due to way olingo // designed it is going to be a big refactoring. .header("Prefer", "return=representation") .send(); assertEquals(201, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"a\":\"teiid\",\"b\":\"dv\"}", response.getContentAsString()); // update to collection based reference payload = "{\n" + " \"a\":\"teiid\",\n" + " \"b\":\"dv\",\n" + " \"y_FKX\": [\n"+ " {"+ " \"a\":\"odata\",\n" + " \"b\":\"teiid\"\n" + " },\n"+ " {\n"+ " \"a\":\"odata4\",\n" + " \"b\":\"teiid\"\n" + " }\n"+ " ],\n"+ " \"z_FKX\": [\n"+ " {"+ " \"a\":\"odata\",\n" + " \"b\":\"teiid\"\n" + " },\n"+ " {\n"+ " \"a\":\"odata4\",\n" + " \"b\":\"olingo4\"\n" + " }\n"+ " ]\n"+ "}"; response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider(payload), ContentType.APPLICATION_JSON.toString()) // when this header is defined the return should be expanded, but due to way olingo // designed it is going to be a big refactoring. .header("Prefer", "return=representation") .send(); assertEquals(201, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"a\":\"teiid\",\"b\":\"dv\"}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testFunction() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/proc(x='foo')"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Edm.String\",\"value\":\"foo\"}", response.getContentAsString()); } @Test public void testFunctionDate() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/getCustomers(p2=2011-09-11T00:00:00Z,p3=2.0)"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Edm.DateTimeOffset\",\"value\":\"2011-09-11T00:00:00Z\"}", response.getContentAsString()); } @Test public void testFunctionReturningResultSet() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/procResultSet(x='foo''bar',y=1)"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Loopy.1.VM1.procResultSet_RSParam)\"," + "\"value\":[{\"x\":\"foo'bar\",\"y\":1}," + "{\"x\":\"second\",\"y\":2}," + "{\"x\":\"third\",\"y\":3}]}", response.getContentAsString()); response = http.GET(baseURL + "/loopy/vm1/procResultSet(x='foo',y='1'"); assertEquals(400, response.getStatus()); response = http.GET(baseURL + "/loopy/vm1/procResultSet(x='foo''bar',y=1)?$filter="+Encoder.encode("y eq 3")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Loopy.1.VM1.procResultSet_RSParam)\"," + "\"value\":[{\"x\":\"third\",\"y\":3}]}", response.getContentAsString()); response = http.GET(baseURL + "/loopy/vm1/procResultSet(x='foo''bar',y=1)?$skip=1&$top=1"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Loopy.1.VM1.procResultSet_RSParam)\"," + "\"value\":[{\"x\":\"second\",\"y\":2}]}", response.getContentAsString()); response = http.GET(baseURL + "/loopy/vm1/procResultSet(x='foo''bar',y=1)?$orderby=y%20desc"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Loopy.1.VM1.procResultSet_RSParam)\"," + "\"value\":[{\"x\":\"third\",\"y\":3}," + "{\"x\":\"second\",\"y\":2}," + "{\"x\":\"foo'bar\",\"y\":1}]}", response.getContentAsString()); } @Test public void testFunctionReturningStream() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/procXML(x='foo')"); assertEquals(200, response.getStatus()); assertEquals("<name>foo</name>", response.getContentAsString()); } @Test public void testFunctionReturningStreamDesignedToReturnTable() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/procComposableXML(x='foo')"); //can't handle multiple lob rows assertEquals(404, response.getStatus()); } @Test public void testFunctionReturningReturningArray() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/getCustomerIds(p1=1)"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Edm.Int32)\",\"value\":[1,2]}", response.getContentAsString()); } @Test public void testActionStream() throws Exception { ContentResponse response = http.newRequest(baseURL + "/loopy/vm1/actionXML") .method("POST") .content(new StringContentProvider("<name>foo2</name>"), "application/xml") .send(); assertEquals(200, response.getStatus()); assertEquals("<name>foo2</name>", response.getContentAsString()); } @Test public void testAllowHeaderOnMethodNotSupported() throws Exception { ContentResponse response = http.newRequest(baseURL + "/loopy/vm1/actionXML") .method("GET") .content(new StringContentProvider("<name>foo2</name>"), "application/xml") .send(); assertEquals(405, response.getStatus()); assertEquals("POST", getHeader(response, "Allow")); } @Test public void testActionSimpleParameters() throws Exception { ContentResponse response = http.newRequest(baseURL + "/loopy/vm1/procActionJSON") .method("POST") .content(new StringContentProvider("{\"x\": \"foo\", \"y\": 4.5}"), "application/json") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"x1\":\"foo\",\"y1\":4.5}", response.getContentAsString()); } @Test public void testMetadataVisibility() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/PM2/G1"); assertEquals(500, response.getStatus()); } @Test public void testCheckGeneratedColumns() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory() { @Override public UpdateExecution createUpdateExecution( org.teiid.language.Command command, ExecutionContext executionContext, RuntimeMetadata metadata, Object connection) throws TranslatorException { GeneratedKeys keys = executionContext.getCommandContext().returnGeneratedKeys( new String[] { "a" },new Class[] { String.class }); keys.addKey(Arrays.asList("ax")); return super.createUpdateExecution(command, executionContext, metadata, connection); } @Override public boolean supportsCompareCriteriaEquals() { return true; } }; hc.addUpdate("INSERT INTO x (b, c) VALUES ('b', 5)", new int[] {1}); // this gets called right after insert. hc.addData("SELECT x.a, x.b, x.c FROM x WHERE x.a = 'ax'", Arrays.asList(Arrays.asList("a", "b", 2))); teiid.addTranslator("x", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a)) options (updatable true);"); mmd.addSourceMapping("x", "x", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider("{\"b\":\"b\", \"c\":5}"), "application/json") .send(); assertEquals(201, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } private UnitTestLocalClient getClient(final TeiidDriver driver, final String vdb, final Properties properties) { return new UnitTestLocalClient(vdb, "1", properties, properties, driver, vdb); } @Test public void testSkipNoPKTable() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/PM1/NoPKTable"); assertEquals(404, response.getStatus()); assertEquals("{\"error\":{\"code\":null,\"message\":\"Cannot find EntitySet, Singleton, " + "ActionImport or FunctionImport with name 'NoPKTable'.\"}}", response.getContentAsString()); } @Test public void testInvalidCharacterReplacement() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("DDL", "create view x (a string primary key, b char, " + "c string[], d integer) as select 'ab\u0000cd\u0001', char(22), " + "('a\u00021','b1'), 1;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); props.setProperty(LocalClient.INVALID_CHARACTER_REPLACEMENT, " "); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/vw/x") .method("GET") .header("Accept", "application/xml") .send(); assertEquals(200, response.getStatus()); String payload = "<a:content type=\"application/xml\">" + "<m:properties><d:a>ab cd </d:a>" + "<d:b> </d:b>" + "<d:c m:type=\"#Collection(String)\">" + "<m:element>a 1</m:element>" + "<m:element>b1</m:element>" + "</d:c>" + "<d:d m:type=\"Int32\">1</d:d>" + "</m:properties>" + "</a:content>"; assertTrue(response.getContentAsString().contains(payload)); response = http.GET(baseURL + "/northwind/vw/x"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"ab\\u0000cd\\u0001\",\"b\":\"\\u0016\",\"c\":[\"a\\u00021\",\"b1\"],\"d\":1}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testArrayResults() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("DDL", "create view x (a string primary key, b integer[], c string[][]) " + "as select 'x', (1, 2, 3), (('a','b'),('c','d')) union " + "select 'y', (4, 5, 6), (('x','y'),('z','u'));"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$format=json&$select=a,b"); assertEquals(200, response.getStatus()); assertEquals( "{\"@odata.context\":\"$metadata#x(a,b)\"," + "\"value\":[{\"a\":\"x\",\"b\":[1,2,3]},{\"a\":\"y\",\"b\":[4,5,6]}]}", response.getContentAsString()); // since there are multi-dimentional array it will be not supported response = http.GET(baseURL + "/northwind/vw/x?$format=json"); assertEquals(501, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void test$ItFilter() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory() { @Override public boolean supportsCompareCriteriaEquals() { return true; } }; hc.addData("SELECT x.c, x.a FROM x WHERE x.a = 'x'", Arrays.asList(Arrays.asList(new String[] {"google.net", "google.com"}, 'x'))); hc.addData("SELECT x.c, x.a FROM x WHERE x.a = 'y'", Arrays.asList(Arrays.asList(new String[] {"example.net", "example.com"}, 'y'))); teiid.addTranslator("x8", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("DDL", "create foreign table x (a string primary key, b integer[], c string[]);"); mmd.setModelType(Model.Type.PHYSICAL); mmd.addSourceMapping("x8", "x8", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.GET(baseURL + "/northwind/vw/x('x')/c?$filter=endswith($it,'com')"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x('x')/c\",\"value\":[\"google.com\"]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x('y')/c?$filter=startswith($it,'example')"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x('y')/c\",\"value\":[\"example.net\",\"example.com\"]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x('y')/c?$filter=startswith($it,'example')&$orderby=$it"); assertEquals(501, response.getStatus()); response = http.GET(baseURL + "/northwind/vw/x('x')/c?$filter=endswith($it,'com')%20or%20endswith($it,'net')"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x('x')/c\",\"value\":[\"google.net\",\"google.com\"]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testArrayInsertResults() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("INSERT INTO x (a, b) VALUES ('x', (1, 2, 3))", new int[] {1}); teiid.addTranslator("x5", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("DDL", "create foreign table x (a string primary key, b integer[], c string[][]) OPTIONS (updatable true);"); mmd.setModelType(Model.Type.PHYSICAL); mmd.addSourceMapping("x5", "x5", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider("{\"a\":\"x\",\"b\":[1,2,3]}"), "application/json") .send(); assertEquals(201, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testArrayUpdateResults() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("UPDATE x SET b = (1, 2, 3) WHERE x.a = 'x'", new int[] {1}); teiid.addTranslator("x6", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("DDL", "create foreign table x (a string primary key, b integer[], c string[][]) OPTIONS (updatable true);"); mmd.setModelType(Model.Type.PHYSICAL); mmd.addSourceMapping("x6", "x6", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x('x')") .method("PATCH") .content(new StringContentProvider("{\"a\":\"x\",\"b\":[1,2,3]}"), "application/json") .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testSkipToken() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); props.setProperty("batch-size", "1"); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$format=json"); assertEquals(200, response.getStatus()); String starts = "{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"abc\",\"b\":456}]," + "\"@odata.nextLink\":\""+baseURL+"/northwind/vw/x?$format=json&$skiptoken="; String ends = ",1\"}"; assertTrue(response.getContentAsString(), response.getContentAsString().startsWith(starts)); assertTrue(response.getContentAsString(), response.getContentAsString().endsWith(ends)); JsonNode node = getJSONNode(response); String nextLink = node.get("@odata.nextLink").asText(); response = http.GET(nextLink); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testSkipTokenNoSystemOptions() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); props.setProperty("batch-size", "1"); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x"); assertEquals(200, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void test$SkipWithNegitive() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$skip=-1"); assertEquals(400, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testAlias() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$filter=" + Encoder.encode("a eq @a") + "&" + Encoder.encode("@a")+"="+Encoder.encode("'xyz'")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testNegitive$Top() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL+ "/northwind/vw/x?$top=-1"); assertEquals(400, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testAliasNoValue() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$filter="+Encoder.encode("a eq @a")); assertEquals(200, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testSkipTokenWithPageSize() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) as " + "select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); ContentResponse response = http.newRequest(baseURL + "/northwind/vw/x?$format=json") .header("Prefer", "odata.maxpagesize=1") .send(); assertEquals(200, response.getStatus()); String starts = "{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"abc\",\"b\":456}]," + "\"@odata.nextLink\":\""+baseURL+"/northwind/vw/x?$format=json&$skiptoken="; String ends = ",1\"}"; assertTrue(response.getContentAsString(), response.getContentAsString().startsWith(starts)); assertTrue(response.getContentAsString(), response.getContentAsString().endsWith(ends)); assertEquals("odata.maxpagesize=1", getHeader(response, "Preference-Applied")); JsonNode node = getJSONNode(response); String nextLink = node.get("@odata.nextLink").asText(); response = http.GET(nextLink); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); } finally { teiid.undeployVDB("northwind"); } } private String getHeader(ContentResponse response, String header) { return response.getHeaders().get(header); } @Test public void testCount() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) " + "as select 'a', 123 " + "union all select 'b', 456 " + "union all select 'c', 789 " + "union all select 'd', 012;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); props.setProperty("batch-size", "1"); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$format=json&$count=true&$top=1&$skip=1"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"@odata.count\":4,\"value\":[{\"a\":\"b\",\"b\":456}]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x?$format=json&$count=true&$filter="+Encoder.encode("a eq 'a'")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"@odata.count\":1,\"value\":[{\"a\":\"a\",\"b\":123}]}", response.getContentAsString()); //effectively the same as above response = http.GET(baseURL + "/northwind/vw/x?$format=json&$count=true&$skip=1"); assertEquals(200, response.getStatus()); String r = "{\"@odata.context\":\"$metadata#x\",\"@odata.count\":4," + "\"value\":[{\"a\":\"b\",\"b\":456}],\"@odata.nextLink\":"; assertTrue(response.getContentAsString(), response.getContentAsString().startsWith(r)); //now there should be a next response = http.GET(baseURL + "/northwind/vw/x?$format=json&$count=true"); assertEquals(200, response.getStatus()); String ends = ",1,4\"}"; String responseStr = response.getContentAsString(); assertTrue(responseStr, responseStr.endsWith(ends)); //Next string JsonParser parser = new JsonFactory(new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true)) .createParser(responseStr); JsonNode node = parser.getCodec().readTree(parser); response = http.newRequest(node.get("@odata.nextLink").asText()) .method("GET") .send(); assertEquals(200, response.getStatus()); responseStr = response.getContentAsString(); assertTrue(responseStr, responseStr.startsWith("{\"@odata.context\":\"$metadata#x\"," + "\"@odata.count\":4," + "\"value\":[{\"a\":\"b\",\"b\":456}]," + "\"@odata.nextLink\":\""+baseURL+"/northwind/vw/x?$format=json&$count=true&$skiptoken=")); response = http.GET(baseURL + "/northwind/vw/x/$count"); assertEquals(200, response.getStatus()); assertEquals("4", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testCompositeKeyUpdates() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("DELETE FROM x WHERE x.a = 'a' AND x.b = 'b'", new int[] {1}); hc.addUpdate("INSERT INTO x (a, b, c) VALUES ('a', 'b', 5)", new int[] {1}); hc.addUpdate("UPDATE x SET c = 10 WHERE x.a = 'a' AND x.b = 'b'", new int[] {1}); hc.addData("SELECT x.a, x.b, x.c FROM x WHERE x.a = 'a' AND x.b = 'b'", Arrays.asList(Arrays.asList("a", "b", 1))); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a, b)) options (updatable true);"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x(a='a',b='b')") .method("DELETE") .send(); assertEquals(204, response.getStatus()); //partial key response = http.newRequest(baseURL + "/northwind/m/x('a')") .method("DELETE") .send(); assertEquals(400, response.getStatus()); //partial key response = http.newRequest(baseURL + "/northwind/m/x(a='a',a='b')") .method("DELETE") .send(); assertEquals(400, response.getStatus()); //not supported //request = new ClientRequest(TestPortProvider.generateURL("/odata/northwind/x(a='a',b='b')/c/$value")); //request.body("text/plain", "5"); //response = request.put(String.class); response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider("{\"a\":\"a\", \"b\":\"b\", \"c\":5}"), "application/json") .send(); assertEquals(201, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x(a='a',b='b')") .method("PATCH") .content(new StringContentProvider("{\"c\":10}"), "application/json") .send(); assertEquals(204, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x(a='a',b='b')") .method("PUT") .content(new StringContentProvider("{\"a\":\"a\", \"b\":\"b\", \"c\":5}"), "application/json") .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testPutFailure() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a, b)) options (updatable true);"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); localClient.setThrowUpdateException(true); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x(a='a',b='b')") .method("PUT") .content(new StringContentProvider("{\"a\":\"a\", \"b\":\"b\", \"c\":5}"), "application/json") .send(); assertEquals(500, response.getStatus()); assertTrue(localClient.isRollback()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testPutRawValue() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("UPDATE x SET c = 6 WHERE x.a = 'a'", new int[] {1}); hc.addUpdate("UPDATE x SET b = '6' WHERE x.a = 'a'", new int[] {1}); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a)) options (updatable true);"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x('a')/c/$value") .method("PUT") .content(new BytesContentProvider("6".getBytes())) .send(); assertEquals(204, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x('a')/b/$value") .method("PUT") .content(new BytesContentProvider("6".getBytes())) .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testEntityId() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("UPDATE x SET c = 6 WHERE x.a = 'a'", new int[] {1}); hc.addUpdate("UPDATE x SET b = '6' WHERE x.a = 'a'", new int[] {1}); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a)) options (updatable true);"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/$entity?$id="+baseURL+"/northwind/m/x('a')&$select=b") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x(b)/$entity\"," + "\"@odata.id\":\""+baseURL+"/northwind/m/x('ABCDEFG')\"," + "\"b\":\"ABCDEFG\"}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testCrossJoin() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("UPDATE y SET b = 'a' WHERE y.a = 'a'", new int[] {1}); teiid.addTranslator("x9", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);"); mmd.addSourceMapping("x9", "x9", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/$crossjoin(x,y)") .method("GET") .send(); assertEquals(200, response.getStatus()); String u = baseURL + "/northwind/m/"; assertEquals("{\"@odata.context\":\"$metadata#Collection(Edm.ComplexType)\"," + "\"value\":[{\"x@odata.navigationLink\":\""+u+"x('ABCDEFG')\"," + "\"y@odata.navigationLink\":\""+u+"y('ABCDEFG')\"}]}", response.getContentAsString()); // TODO: OLINGO-904 /* response = http.newRequest(baseURL + "/northwind/m/$crossjoin(x,y)?$expand=x") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(Edm.ComplexType)\",\"value\":[{\"x\":{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"},\"y@odata.navigationLink\":\""+u+"y('ABCDEFG')\"}]}", response.getContentAsString()); */ } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testNavigationLinks() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("UPDATE y SET b = 'a' WHERE y.a = 'a'", new int[] {1}); teiid.addTranslator("x4", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);"); mmd.addSourceMapping("x4", "x4", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x('a')/y_FKX/$ref") .method("GET") .send(); assertEquals(200, response.getStatus()); String url = baseURL + "/northwind/m/"; assertEquals("{\"@odata.context\":\"$metadata#Collection($ref)\"," + "\"value\":[{\"@odata.id\":\""+url+"y('ABCDEFG')\"}]}", response.getContentAsString()); // update to collection based reference String payload = "{\n" + "\"@odata.id\": \"/odata4/northwind/m/y('a')\"\n" + "}"; response = http.newRequest(baseURL + "/northwind/m/x('a')/y_FKX/$ref") .method("POST") .content(new StringContentProvider(payload), ContentType.APPLICATION_JSON.toString()) .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testRelatedEntities() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addData("SELECT x.a, x.b FROM x WHERE x.a = 'xa1'", Arrays.asList(Arrays.asList("xa1", "xb"))); hc.addData("SELECT y.a, y.b FROM y WHERE y.b = 'xa1'", Arrays.asList(Arrays.asList("ya1", "xa1"), Arrays.asList("ya2", "xa1"))); // 1-many hc.addData("SELECT x.a FROM x WHERE x.a = 'xa2'", Arrays.asList(Arrays.asList("xa2"))); hc.addData("SELECT y.a, y.b FROM y WHERE y.b = 'xa2'", new ArrayList<List<?>>()); // 1-1 hc.addData("SELECT z.a FROM z WHERE z.a = 'xa3'", Arrays.asList(Arrays.asList("xa3"))); hc.addData("SELECT x.a, x.b FROM x WHERE x.a = 'xa3'", new ArrayList<List<?>>()); teiid.addTranslator("x7", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);" + "create foreign table z (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (a) REFERENCES x(a)" + ") options (updatable true);"); mmd.addSourceMapping("x7", "x7", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; // single 1-many relation response = http.newRequest(baseURL + "/northwind/m/x('xa2')/y_FKX") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#y\",\"value\":[]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/z('xa3')/FKX") .method("GET") .send(); assertEquals(204, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testExpandSimple() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); teiid.addTranslator("x7", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);" + "create foreign table z (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (a) REFERENCES x(a)" + ") options (updatable true);"); mmd.addSourceMapping("x7", "x7", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"ABCDEFG\"," + "\"b\":\"ABCDEFG\",\"y_FKX\":[{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"}]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX&$select=a") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#z(a)\",\"value\":[{\"a\":\"ABCDEFG\"," + "\"FKX\":{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"}}]}", response.getContentAsString()); // explictly selecting and expanding response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX&$select=a") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#z(a)\",\"value\":[{\"a\":\"ABCDEFG\"," + "\"FKX\":{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"}}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX($select=a)") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#z(FKX(a))\",\"value\":[{\"a\":\"ABCDEFG\"," + "\"b\":\"ABCDEFG\",\"FKX\":{\"a\":\"ABCDEFG\"}}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#z\",\"value\":[{\"a\":\"ABCDEFG\"," + "\"b\":\"ABCDEFG\",\"FKX\":{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"}}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX($top=1)") .method("GET") .send(); assertEquals(200, response.getStatus()); /* TODO response = http.newRequest(baseURL + "/northwind/m/z?$expand=FKX/a&$select=a") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#z(a,FKX/a)\",\"value\":[{\"a\":\"ABCDEFG\",\"FKX\":{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\"}}]}", response.getContentAsString()); */ } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testExpandSimple2() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT x.a, x.b FROM x", Arrays.asList(Arrays.asList("xa1", "xb"), Arrays.asList("xa2", "xb2"))); hc.addData("SELECT y.b, y.a FROM y", Arrays.asList(Arrays.asList("xa1", "ya1"), Arrays.asList("xa1", "ya2"))); teiid.addTranslator("x7", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);" + "create foreign table z (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (a) REFERENCES x(a)" + ") options (updatable true);"); mmd.addSourceMapping("x7", "x7", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/x?$expand="+Encoder.encode("y_FKX($filter=b eq 'xa1')")) .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\"," + "\"value\":[" + "{\"a\":\"xa1\",\"b\":\"xb\"," + "\"y_FKX\":[{\"a\":\"ya1\",\"b\":\"xa1\"}," + "{\"a\":\"ya2\",\"b\":\"xa1\"}]}," + "{\"a\":\"xa2\",\"b\":\"xb2\"," + "\"y_FKX\":[]}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testExpandComplex() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT x.a, x.b FROM x", Arrays.asList(Arrays.asList("a", "b"))); hc.addData("SELECT y.b, y.a FROM y", Arrays.asList(Arrays.asList("a", "y"), Arrays.asList("a", "y1"))); hc.addData("SELECT y.a, y.b FROM y", Arrays.asList(Arrays.asList("y", "a"), Arrays.asList("y1","a"))); hc.addData("SELECT z.a, z.b FROM z", Arrays.asList(Arrays.asList("a", "y"))); hc.addData("SELECT z.b, z.a FROM z", Arrays.asList(Arrays.asList("y", "a"))); hc.addData("SELECT tree.a, tree.b FROM tree", Arrays.asList(Arrays.asList("1", "2"), Arrays.asList("2", "3"), Arrays.asList("3", "1"))); hc.addData("SELECT tree.b, tree.a FROM tree", Arrays.asList(Arrays.asList("2", "1"), Arrays.asList("3", "2"), Arrays.asList("1", "3"))); teiid.addTranslator("x7", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (" + " a string, " + " b string, " + " primary key (a)" + ") options (updatable true);" + "create foreign table y (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (b) REFERENCES x(a)" + ") options (updatable true);" + "create foreign table z (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT FKX FOREIGN KEY (a) REFERENCES x(a)," + " CONSTRAINT FKY FOREIGN KEY (b) REFERENCES y(a)" + ") options (updatable true);" + "create foreign table tree (" + " a string, " + " b string, " + " primary key (a)," + " CONSTRAINT parent FOREIGN KEY (b) REFERENCES tree(a)" + ");"); mmd.addSourceMapping("x7", "x7", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX($expand=z_FKY)") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"a\",\"b\":\"b\",\"y_FKX\":" + "[{\"a\":\"y\",\"b\":\"a\",\"z_FKY\":[{\"a\":\"a\",\"b\":\"y\"}]},{\"a\":\"y1\",\"b\":\"a\",\"z_FKY\":[]}]}" + "]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX,z_FKX") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"a\",\"b\":\"b\",\"y_FKX\":" + "[{\"a\":\"y\",\"b\":\"a\"},{\"a\":\"y1\",\"b\":\"a\"}]," + "\"z_FKX\":{\"a\":\"a\",\"b\":\"y\"}}" + "]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=*") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"a\",\"b\":\"b\",\"y_FKX\":" + "[{\"a\":\"y\",\"b\":\"a\"},{\"a\":\"y1\",\"b\":\"a\"}]," + "\"z_FKX\":{\"a\":\"a\",\"b\":\"y\"}}" + "]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX($filter=a%20eq%20'y1'),*") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"a\",\"b\":\"b\",\"y_FKX\":" + "[{\"a\":\"y1\",\"b\":\"a\"}]," + "\"z_FKX\":{\"a\":\"a\",\"b\":\"y\"}}" + "]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX,y_FKX") .method("GET") .send(); assertEquals(400, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=*($levels=3)") .method("GET") .send(); assertEquals(200, response.getStatus()); String expected = "{" + "\"@odata.context\":\"$metadata#x\"," + "\"value\":[" + "{" + "\"a\":\"a\"," + "\"b\":\"b\"," + "\"y_FKX\":[" + "{" + "\"a\":\"y\"," + "\"b\":\"a\"," + "\"FKX\":" + "{" + "\"@odata.id\":\""+baseURL+"/northwind/m/x('a')\"" + "}" + "," + "\"z_FKY\":[" + "{" + "\"a\":\"a\"," + "\"b\":\"y\"," + "\"FKX\":{" + "\"@odata.id\":\""+baseURL+"/northwind/m/x('a')\"" + "}," + "\"FKY\":" + "{" + "\"@odata.id\":\""+baseURL+"/northwind/m/y('y')\"" + "}" + "" + "}" + "]" + "}," + "{" + "\"a\":\"y1\"," + "\"b\":\"a\"," + "\"FKX\":" + "{" + "\"@odata.id\":\""+baseURL+"/northwind/m/x('a')\"" + "}" + "," + "\"z_FKY\":[" + "]" + "}" + "]," + "\"z_FKX\":{" + "\"a\":\"a\"," + "\"b\":\"y\"," + "\"FKX\":{" + "\"@odata.id\":\""+baseURL+"/northwind/m/x('a')\"" + "}," + "\"FKY\":" + "{" + "\"a\":\"y\"," + "\"b\":\"a\"," + "\"FKX\":" + "{" + "\"@odata.id\":\""+baseURL+"/northwind/m/x('a')\"" + "}" + "," + "\"z_FKY\":[" + "{" + "\"@odata.id\":\""+baseURL+"/northwind/m/z('a')\"" + "}" + "]" + "}" + "" + "}" + "}" + "]" + "}"; assertEquals(expected, response.getContentAsString()); //invalid it's not a self relationship response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX($levels=1)") .method("GET") .send(); assertEquals(400, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x?$expand=y_FKX($filter=$it/b%20eq%20a)") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[" + "{\"a\":\"a\",\"b\":\"b\",\"y_FKX\":" + "[]}" + "]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testBatch() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addUpdate("DELETE FROM x WHERE x.a = 'a' AND x.b = 'b'", new int[] {1}); teiid.addTranslator("x", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b string, c integer, " + "primary key (a, b)) options (updatable true);"); mmd.addSourceMapping("x", "x", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); final String batch = "" + "--batch_8194-cf13-1f56" + CRLF + MIME_HEADERS + CRLF + "GET "+baseURL+"/northwind/m/x HTTP/1.1" + CRLF + "Accept: application/json" + CRLF + "MaxDataServiceVersion: 4.0" + CRLF + CRLF + CRLF + "--batch_8194-cf13-1f56" + CRLF + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + CRLF + "--changeset_f980-1cb6-94dd" + CRLF + "content-type: Application/http" + CRLF + "content-transfer-encoding: Binary" + CRLF + "Content-ID: 1" + CRLF + CRLF + "DELETE "+baseURL+"/northwind/m/x(a='a',b='b') HTTP/1.1" + CRLF + "Content-type: application/json" + CRLF + CRLF + CRLF + "--changeset_f980-1cb6-94dd--" + CRLF + "--batch_8194-cf13-1f56--"; ContentResponse response = http.newRequest(baseURL + "/northwind/m/$batch") .method("POST") .content(new StringContentProvider(batch), "multipart/mixed;boundary=batch_8194-cf13-1f56") .send(); assertEquals(202, response.getStatus()); /* String expected = "--batch_d06279e4-c510-46ed-a778-e4e941dfd6f1\n" + "Content-Type: application/http\n" + "Content-Transfer-Encoding: binary\n" + "\n" + "HTTP/1.1 200 OK\n" + "Content-Type: application/json;odata.metadata=minimal\n" + "Content-Length: 78\n" + "\n" + "{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"ABCDEFG\",\"b\":\"ABCDEFG\",\"c\":0}]}\n" + "--batch_d06279e4-c510-46ed-a778-e4e941dfd6f1\n" + "Content-Type: multipart/mixed; boundary=changeset_5a1cba47-b51f-46c2-b0ac-ead23fa7706d\n" + "\n" + "--changeset_5a1cba47-b51f-46c2-b0ac-ead23fa7706d\n" + "Content-Type: application/http\n" + "Content-Transfer-Encoding: binary\n" + "Content-Id: 1\n" + "\n" + "HTTP/1.1 204 No Content\n" + "Content-Length: 0\n" + "\n" + "\n" + "--changeset_5a1cba47-b51f-46c2-b0ac-ead23fa7706d--\n" + "--batch_d06279e4-c510-46ed-a778-e4e941dfd6f1--"; assertEquals(expected, response.getContentAsString()); */ } finally { localClient = null; teiid.undeployVDB("northwind"); } } static class ODataHardCodedExecutionFactory extends HardCodedExecutionFactory{ @Override public boolean supportsCompareCriteriaEquals() { return true; } @Override protected List<? extends List<?>> getData( QueryExpression command) { if (super.getData(command) != null) { List<? extends List<?>> results = super.getData(command); return results; } Class<?>[] colTypes = command.getProjectedQuery().getColumnTypes(); List<Expression> cols = new ArrayList<Expression>(); for (int i = 0; i < colTypes.length; i++) { ElementSymbol elementSymbol = new ElementSymbol("X"); elementSymbol.setType(colTypes[i]); cols.add(elementSymbol); } return (List)Arrays.asList(AutoGenDataService.createResults(cols, 1, false)); } } private HardCodedExecutionFactory buildHardCodedExecutionFactory() { return new ODataHardCodedExecutionFactory(); } @Test public void testJsonProcedureResultSet() throws Exception { try { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("EXEC x()", Arrays.asList(Arrays.asList("x"), Arrays.asList("y"))); teiid.addTranslator("x2", hc); ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign procedure x () returns table(y string) OPTIONS(UPDATECOUNT 0);"); mmd.addSourceMapping("x2", "x2", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.GET(baseURL + "/northwind/m/x()?$format=json"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Collection(northwind.1.m.x_RSParam)\"," + "\"value\":[{\"y\":\"x\"},{\"y\":\"y\"}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testBasicTypes() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMapping("x3", "x3", null); MetadataStore ms = RealMetadataFactory.exampleBQTStore(); Schema s = ms.getSchema("BQT1"); KeyRecord pk = new KeyRecord(KeyRecord.Type.Primary); Table smalla = s.getTable("SmallA"); pk.setName("pk"); pk.addColumn(smalla.getColumnByName("IntKey")); smalla.setPrimaryKey(pk); String ddl = DDLStringVisitor.getDDLString(s, EnumSet.allOf(SchemaObjectType.class), "SmallA"); mmd.addSourceMetadata("DDL", ddl); HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); teiid.addTranslator("x3", hc); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response= http.GET(baseURL + "/northwind/m/SmallA?$format=json&$select=TimeValue"); assertEquals(200, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testCompositeKeyTimestamp() throws Exception { HardCodedExecutionFactory hc = buildHardCodedExecutionFactory(); hc.addData("SELECT x.a, x.b, x.c FROM x WHERE x.a = 'a' AND x.b = {ts '2011-09-11T00:00:00'}", Arrays.asList(Arrays.asList("a", TimestampUtil.createTimestamp(111, 8, 11, 0, 0, 0, 0), 1))); hc.addUpdate("INSERT INTO x (a, b) VALUES ('b', {ts '2000-02-02 22:22:22.0'})", new int[] {1}); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b timestamp, c integer, " + "primary key (a, b)) options (updatable true);"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("POST") .content(new StringContentProvider("{\"a\":\"b\", \"b\":\"2000-02-02T22:22:22Z\"}"), "application/json") .send(); assertEquals(201, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x(a='a',b=2011-09-11T00:00:00Z)") .method("GET") .send(); assertEquals(200, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testStreamProperties() throws Exception { ContentResponse response = http.newRequest(baseURL + "/loopy/vm1/LobTable(2)/e2") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("<name>content2</name>", response.getContentAsString()); response = http.newRequest(baseURL + "/loopy/vm1/LobTable") .method("GET") .send(); assertEquals(200, response.getStatus()); String string = response.getContentAsString(); // stream properties are computed, not shown in the payload. assertFalse(string.contains("odata4/loopy/vm1/LobTable(1)/e2")); assertFalse(string.contains("odata4/loopy/vm1/LobTable(2)/e2")); } @Test public void testWithAlternateContext() throws Exception { http.stop(); server.stop(); Map<String, String> props = new HashMap<String, String>(); props.put("vdb-name", "loopy"); props.put("vdb-version", "1"); createContext("/other", props); ContentResponse response = http.newRequest(baseURL + "/vm1/LobTable(2)/e2") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("<name>content2</name>", response.getContentAsString()); } @Test public void testNonExistentEntity() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT x.a, x.b FROM x", Arrays.asList(Arrays.asList("a", 1))); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b integer, primary key (a));"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x('b')") .method("GET") .send(); assertEquals(404, response.getStatus()); response = http.newRequest(baseURL + "/northwind/m/x('b')/b") .method("GET") .send(); assertEquals(404, response.getStatus()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testInvalidResource() throws Exception { http.stop(); server.stop(); Map<String, String> props = new HashMap<String, String>(); props.put("vdb-name", "loopy"); props.put("vdb-version", "1"); createContext("/other", props); ContentResponse response = http.newRequest(baseURL + "/vm1/Foo") .method("GET") .send(); assertEquals(404, response.getStatus()); assertEquals("{\"error\":{\"code\":null,\"message\":\"Cannot find EntitySet, Singleton, " + "ActionImport or FunctionImport with name 'Foo'.\"}}", response.getContentAsString()); } @Test public void testErrorCodes() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory() { @Override public ResultSetExecution createResultSetExecution( final QueryExpression command, ExecutionContext executionContext, RuntimeMetadata metadata, Object connection) throws TranslatorException { List<? extends List<?>> list = getData(command); if (list == null) { throw new RuntimeException(command.toString()); } final Iterator<? extends List<?>> result = list.iterator(); return new ResultSetExecution() { @Override public void execute() throws TranslatorException { throw new TranslatorException(ODataPlugin.Event.TEIID16001, "execution failed"); } @Override public void close() { } @Override public void cancel() throws TranslatorException { } @Override public List<?> next() throws TranslatorException, DataNotAvailableException { if (result.hasNext()) { return result.next(); } return null; } }; } }; hc.addData("SELECT x.a, x.b FROM x", Arrays.asList(Arrays.asList("a", 1))); teiid.addTranslator("x1", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "create foreign table x (a string, b integer, primary key (a));"); mmd.addSourceMapping("x1", "x1", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = http.newRequest(baseURL + "/northwind/m/x") .method("GET") .send(); assertEquals(400, response.getStatus()); assertEquals("{\"error\":{\"code\":\"TEIID30504\"," + "\"message\":\"TEIID30504 x1: TEIID16001 execution failed\"}}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/x?$format=xml") .method("GET") .send(); assertEquals(400, response.getStatus()); assertEquals("<?xml version='1.0' encoding='UTF-8'?>" + "<error xmlns=\"http://docs.oasis-open.org/odata/ns/metadata\">" + "<code>TEIID30504</code>" + "<message>TEIID30504 x1: TEIID16001 execution failed</message>" + "</error>", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testFilterNull() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) as " + "select 'xyz', 123 union all " + "select 'abc', null;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$filter="+Encoder.encode("b eq null")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"abc\",\"b\":null}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testMultipleAirthamatic() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/pm1/G1?$filter="+Encoder.encode("e2 eq 1 add 1 add 1")); assertEquals(200, response.getStatus()); } @Test public void testFloor() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/pm1/G1?$filter="+Encoder.encode("e2 eq floor(4.2)")); assertEquals(200, response.getStatus()); } @Test public void testRound() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/pm1/G1?$filter="+Encoder.encode("e2 eq round(4.2)")); assertEquals(200, response.getStatus()); } @Test public void test$allNotImplemented() throws Exception { ContentResponse response = http.GET(baseURL + "/loopy/vm1/$all"); assertEquals(501, response.getStatus()); } @Test public void testExpand() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT Customers.id, Customers.name FROM Customers", Arrays.asList(Arrays.asList(1, "customer1"), Arrays.asList(2, "customer2"), Arrays.asList(3, "customer3"), Arrays.asList(4, "customer4"))); hc.addData("SELECT Orders.customerid, Orders.id, Orders.place FROM Orders", Arrays.asList(Arrays.asList(1, 1, "town"), Arrays.asList(1, 2, "state"), Arrays.asList(1, 3, "country"), Arrays.asList(1,4, "abroad"), Arrays.asList(2, 5, "state"), Arrays.asList(2, 6, "country"), Arrays.asList(3,7,"town"), Arrays.asList(3, 8, "town"))); hc.addData("SELECT Orders.place, Orders.customerid, Orders.id FROM Orders", Arrays.asList(Arrays.asList("town",1, 1), Arrays.asList("state", 1, 2), Arrays.asList("country",1, 3), Arrays.asList("abroad", 1, 4), Arrays.asList("state", 2, 5), Arrays.asList("country", 2, 6), Arrays.asList("town", 3, 7), Arrays.asList("town", 3, 8))); teiid.addTranslator("x12", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "CREATE FOREIGN TABLE Customers (\n" + " id integer PRIMARY KEY OPTIONS (NAMEINSOURCE 'id'),\n" + " name varchar(10));\n" + "CREATE FOREIGN TABLE Orders (\n" + " id integer PRIMARY KEY OPTIONS (NAMEINSOURCE 'id'),\n" + " customerid integer,\n" + " place varchar(10),\n" + " FOREIGN KEY (customerid) REFERENCES Customers(id));"); mmd.addSourceMapping("x12", "x12", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0&$count=true") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"@odata.count\":4,\"" + "value\":[" + "{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0\":[" + "{\"id\":1,\"customerid\":1,\"place\":\"town\"}," + "{\"id\":2,\"customerid\":1,\"place\":\"state\"}," + "{\"id\":3,\"customerid\":1,\"place\":\"country\"}," + "{\"id\":4,\"customerid\":1,\"place\":\"abroad\"}" + "]}," + "{\"id\":2,\"name\":\"customer2\"," + "\"Orders_FK0\":[" + "{\"id\":5,\"customerid\":2,\"place\":\"state\"}," + "{\"id\":6,\"customerid\":2,\"place\":\"country\"}" + "]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0\":[" + "{\"id\":7,\"customerid\":3,\"place\":\"town\"}," + "{\"id\":8,\"customerid\":3,\"place\":\"town\"}" + "]}," + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0\":[" + "]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0&$count=true&$skip=3") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"@odata.count\":4,\"value\":[" + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0\":[]" + "}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0&$skip=2") .method("GET") .header("Prefer", "odata.maxpagesize=1") .send(); assertEquals(200, response.getStatus()); assertTrue(response.getContentAsString().startsWith("{\"@odata.context\":\"$metadata#Customers\"," + "\"value\":[{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0\":[" + "{\"id\":7,\"customerid\":3,\"place\":\"town\"}," + "{\"id\":8,\"customerid\":3,\"place\":\"town\"}" + "]}]," + "\"@odata.nextLink\":\"http://localhost:")); assertTrue(response.getContentAsString(), response.getContentAsString().endsWith(",1\"}")); JsonParser parser = new JsonFactory(new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true)) .createParser(response.getContentAsString()); JsonNode node = parser.getCodec().readTree(parser); response = http.newRequest(node.get("@odata.nextLink").asText()) .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"value\":[" + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0\":[]" + "}]}", response.getContentAsString()); // system options response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0($skip=2)&$count=true") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"@odata.count\":4,\"" + "value\":[" + "{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0\":[" + "{\"id\":3,\"customerid\":1,\"place\":\"country\"}," + "{\"id\":4,\"customerid\":1,\"place\":\"abroad\"}" + "]}," + "{\"id\":2,\"name\":\"customer2\"," + "\"Orders_FK0\":[" + "]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0\":[" + "]}," + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0\":[" + "]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0($top=2;$count=true)&$count=true") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"@odata.count\":4,\"" + "value\":[" + "{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0@odata.count\":4," + "\"Orders_FK0\":[" + "{\"id\":1,\"customerid\":1,\"place\":\"town\"}," + "{\"id\":2,\"customerid\":1,\"place\":\"state\"}" + "]}," + "{\"id\":2,\"name\":\"customer2\"," + "\"Orders_FK0@odata.count\":2," + "\"Orders_FK0\":[" + "{\"id\":5,\"customerid\":2,\"place\":\"state\"}," + "{\"id\":6,\"customerid\":2,\"place\":\"country\"}" + "]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0@odata.count\":2," + "\"Orders_FK0\":[" + "{\"id\":7,\"customerid\":3,\"place\":\"town\"}," + "{\"id\":8,\"customerid\":3,\"place\":\"town\"}" + "]}," + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0@odata.count\":0," + "\"Orders_FK0\":[" + "]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0($top=1;$select=place)&$count=true") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers(Orders_FK0(place))\"," + "\"@odata.count\":4,\"" + "value\":[" + "{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0\":[" + "{\"@odata.id\":\""+baseURL+"/northwind/m/Orders(1)\",\"place\":\"town\"}" + "]}," + "{\"id\":2,\"name\":\"customer2\"," + "\"Orders_FK0\":[" + "{\"@odata.id\":\""+baseURL+"/northwind/m/Orders(5)\",\"place\":\"state\"}" + "]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0\":[" + "{\"@odata.id\":\""+baseURL+"/northwind/m/Orders(7)\",\"place\":\"town\"}" + "]}," + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0\":[" + "]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0($filter="+Encoder.encode("place eq ")+"'town')") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"value\":[{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0\":[{\"id\":1,\"customerid\":1,\"place\":\"town\"}]}," + "{\"id\":2,\"name\":\"customer2\",\"Orders_FK0\":[]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0\":[{\"id\":7,\"customerid\":3,\"place\":\"town\"}," + "{\"id\":8,\"customerid\":3,\"place\":\"town\"}]}," + "{\"id\":4,\"name\":\"customer4\",\"Orders_FK0\":[]}]}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Customers?$expand=Orders_FK0($top=0;$count=true)&$count=true") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"@odata.count\":4,\"" + "value\":[" + "{\"id\":1,\"name\":\"customer1\"," + "\"Orders_FK0@odata.count\":4," + "\"Orders_FK0\":[]}," + "{\"id\":2,\"name\":\"customer2\"," + "\"Orders_FK0@odata.count\":2," + "\"Orders_FK0\":[]}," + "{\"id\":3,\"name\":\"customer3\"," + "\"Orders_FK0@odata.count\":2," + "\"Orders_FK0\":[]}," + "{\"id\":4,\"name\":\"customer4\"," + "\"Orders_FK0@odata.count\":0," + "\"Orders_FK0\":[" + "]}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testIndexingOfStringFunctions() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "create view x (a string primary key, b integer) as " + "select 'xyz', 123 union all select 'abc', 456;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/x?$filter=" +Encoder.encode("indexof(a,'y') eq 1")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x?$filter=" +Encoder.encode("indexof(a,'y') eq 2")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x?$filter=" +Encoder.encode("substring(a,1) eq 'yz'")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x?$filter=" +Encoder.encode("substring(a,1,2) eq 'yz'")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"xyz\",\"b\":123}]}", response.getContentAsString()); response = http.GET(baseURL + "/northwind/vw/x?$filter=" +Encoder.encode("substring(a,0,1) eq 'a'")); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#x\",\"value\":[{\"a\":\"abc\",\"b\":456}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testMonthFunctions() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "CREATE VIEW SimpleTable(\n" + " intkey integer PRIMARY KEY,\n" + " intnum integer,\n" + " stringkey varchar(20),\n" + " stringval varchar(20),\n" + " booleanval boolean,\n" + " decimalval decimal(20, 10),\n" + " timeval time,\n" + " dateval date,\n" + " timestampval timestamp,\n" + " clobval clob) as select 1,1, '1','1',true,1.0,{t '00:01:01'}, " + "{d '2001-01-01'},{ts '2001-01-01 00:01:01.01'},null;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/SimpleTable?$filter=" +Encoder.encode("month(2001-01-01T00:01:01.01Z) eq intkey")+"&$select=intkey"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#SimpleTable(intkey)\",\"value\":[{\"intkey\":1}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testReverseNavigation() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT Customers.id, Customers.name FROM Customers", Arrays.asList(Arrays.asList(1, "customer1"), Arrays.asList(2, "customer2"), Arrays.asList(3, "customer3"), Arrays.asList(4, "customer4"))); hc.addData("SELECT Customers.id FROM Customers", Arrays.asList(Arrays.asList(1), Arrays.asList(2), Arrays.asList(3), Arrays.asList(4))); hc.addData("SELECT Orders.id, Orders.customerid FROM Orders", Arrays.asList(Arrays.asList(1, 1), Arrays.asList(2, 1), Arrays.asList(3,1), Arrays.asList(4,1), Arrays.asList(5,2), Arrays.asList(6,2), Arrays.asList(7,3), Arrays.asList(8,3))); hc.addData("SELECT Orders.id, Orders.customerid, Orders.place FROM Orders", Arrays.asList(Arrays.asList(1, 1, "town"), Arrays.asList(2, 1, "state"), Arrays.asList(3, 1,"country"), Arrays.asList(4, 1, "abroad"), Arrays.asList(5,2, "state"), Arrays.asList(6,2, "country"), Arrays.asList(7,3,"town"), Arrays.asList(8,3, "town"))); hc.addData("SELECT Orders.customerid, Orders.id, Orders.place FROM Orders", Arrays.asList(Arrays.asList(1, 1, "town"), Arrays.asList(1, 2, "state"), Arrays.asList(1,3, "country"), Arrays.asList(1, 4, "abroad"), Arrays.asList(2,5, "state"), Arrays.asList(2, 6, "country"), Arrays.asList(3,7,"town"), Arrays.asList(3,8, "town"))); teiid.addTranslator("x12", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "CREATE FOREIGN TABLE Customers (\n" + " id integer PRIMARY KEY OPTIONS (NAMEINSOURCE 'id'),\n" + " name varchar(10));\n" + "CREATE FOREIGN TABLE Orders (\n" + " id integer PRIMARY KEY OPTIONS (NAMEINSOURCE 'id'),\n" + " customerid integer,\n" + " place varchar(10),\n" + " CONSTRAINT Customer FOREIGN KEY (customerid) REFERENCES Customers(id));"); mmd.addSourceMapping("x12", "x12", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/Orders(1)/Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers/$entity\"," + "\"id\":1,\"name\":\"customer1\"}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Orders(1)?$expand=Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Orders/$entity\"," + "\"id\":1,\"customerid\":1,\"place\":\"town\"," + "\"Customer\":{\"id\":1,\"name\":\"customer1\"}}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Orders(1)/Customer/Orders_Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"value\":[{\"id\":1,\"customerid\":1,\"place\":\"town\"}," + "{\"id\":2,\"customerid\":1,\"place\":\"state\"}," + "{\"id\":3,\"customerid\":1,\"place\":\"country\"}," + "{\"id\":4,\"customerid\":1,\"place\":\"abroad\"}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testReverseNavigationWithUniqueKey() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT Customers.id, Customers.name FROM Customers", Arrays.asList(Arrays.asList(1, "customer1"), Arrays.asList(2, "customer2"), Arrays.asList(3, "customer3"), Arrays.asList(4, "customer4"))); hc.addData("SELECT Customers.id FROM Customers", Arrays.asList(Arrays.asList(1), Arrays.asList(2), Arrays.asList(3), Arrays.asList(4))); hc.addData("SELECT Orders.id, Orders.customerid FROM Orders", Arrays.asList(Arrays.asList(1, 1), Arrays.asList(2, 1), Arrays.asList(3,1), Arrays.asList(4,1), Arrays.asList(5,2), Arrays.asList(6,2), Arrays.asList(7,3), Arrays.asList(8,3))); hc.addData("SELECT Orders.id, Orders.customerid, Orders.place FROM Orders", Arrays.asList(Arrays.asList(1, 1, "town"), Arrays.asList(2, 1, "state"), Arrays.asList(3, 1,"country"), Arrays.asList(4, 1, "abroad"), Arrays.asList(5,2, "state"), Arrays.asList(6,2, "country"), Arrays.asList(7,3,"town"), Arrays.asList(8,3, "town"))); hc.addData("SELECT Orders.customerid, Orders.id, Orders.place FROM Orders", Arrays.asList(Arrays.asList(1, 1, "town"), Arrays.asList(1, 2, "state"), Arrays.asList(1,3, "country"), Arrays.asList(1, 4, "abroad"), Arrays.asList(2,5, "state"), Arrays.asList(2, 6, "country"), Arrays.asList(3,7,"town"), Arrays.asList(3,8, "town"))); teiid.addTranslator("x12", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "CREATE FOREIGN TABLE Customers (\n" + " id integer UNIQUE OPTIONS (NAMEINSOURCE 'id'),\n" + " name varchar(10));\n" + "CREATE FOREIGN TABLE Orders (\n" + " id integer PRIMARY KEY OPTIONS (NAMEINSOURCE 'id'),\n" + " customerid integer,\n" + " place varchar(10),\n" + " CONSTRAINT Customer FOREIGN KEY (customerid) REFERENCES Customers(id));"); mmd.addSourceMapping("x12", "x12", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/Orders(1)/Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers/$entity\"," + "\"id\":1,\"name\":\"customer1\"}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Orders(1)?$expand=Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Orders/$entity\"," + "\"id\":1,\"customerid\":1,\"place\":\"town\"," + "\"Customer\":{\"id\":1,\"name\":\"customer1\"}}", response.getContentAsString()); response = http.newRequest(baseURL + "/northwind/m/Orders(1)/Customer/Orders_Customer") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#Customers\"," + "\"value\":[{\"id\":1,\"customerid\":1,\"place\":\"town\"}," + "{\"id\":2,\"customerid\":1,\"place\":\"state\"}," + "{\"id\":3,\"customerid\":1,\"place\":\"country\"}," + "{\"id\":4,\"customerid\":1,\"place\":\"abroad\"}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testReverseBidirectionalNavigation() throws Exception { HardCodedExecutionFactory hc = new HardCodedExecutionFactory(); hc.addData("SELECT EmployeeMasterEntity.EmployeeID, EmployeeMasterEntity.Department FROM EmployeeMasterEntity", Arrays.asList(Arrays.asList(3, 10000001))); hc.addData("SELECT OrganizationalUnitEntity.OrganizationaUnitID, OrganizationalUnitEntity.UnitManager FROM OrganizationalUnitEntity", Arrays.asList(Arrays.asList(10000001, 1))); teiid.addTranslator("x12", hc); try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("m"); mmd.addSourceMetadata("ddl", "CREATE FOREIGN TABLE EmployeeMasterEntity (\n" + " EmployeeID integer primary key,\n" + " Department integer," + "CONSTRAINT Departments FOREIGN KEY (Department) REFERENCES OrganizationalUnitEntity(OrganizationaUnitID));\n" + "CREATE FOREIGN TABLE OrganizationalUnitEntity (\n" + " OrganizationaUnitID integer PRIMARY KEY,\n" + " UnitManager integer,\n" + " CONSTRAINT Managers FOREIGN KEY (UnitManager) REFERENCES EmployeeMasterEntity(EmployeeID));"); mmd.addSourceMapping("x12", "x12", null); teiid.deployVDB("northwind", mmd); localClient = getClient(teiid.getDriver(), "northwind", new Properties()); ContentResponse response = null; response = http.newRequest(baseURL + "/northwind/m/EmployeeMasterEntity(3)/Departments?$format=json") .method("GET") .send(); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#OrganizationalUnitEntity/$entity\",\"OrganizationaUnitID\":10000001,\"UnitManager\":1}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } @Test public void testDecimalPrecisionScale() throws Exception { try { ModelMetaData mmd = new ModelMetaData(); mmd.setName("vw"); mmd.addSourceMetadata("ddl", "CREATE VIEW SimpleTable(\n" + " intkey integer PRIMARY KEY,\n" + " decimalval decimal(3, 1)) as select 1,12.31 union all select 2, 1.0001 union all select 3, 123.1;"); mmd.setModelType(Model.Type.VIRTUAL); teiid.deployVDB("northwind", mmd); Properties props = new Properties(); localClient = getClient(teiid.getDriver(), "northwind", props); ContentResponse response = http.GET(baseURL + "/northwind/vw/SimpleTable"); assertEquals(200, response.getStatus()); assertEquals("{\"@odata.context\":\"$metadata#SimpleTable\",\"value\":[{\"intkey\":1,\"decimalval\":12.3},{\"intkey\":2,\"decimalval\":1.0},{\"intkey\":3,\"decimalval\":123}]}", response.getContentAsString()); } finally { localClient = null; teiid.undeployVDB("northwind"); } } }