/* * 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.translator.odata; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.activation.DataSource; import javax.xml.ws.Dispatch; import javax.xml.ws.Service.Mode; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.http.HTTPBinding; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.odata4j.edm.EdmDataServices; import org.odata4j.format.xml.EdmxFormatParser; import org.odata4j.stax2.util.StaxUtil; import org.teiid.adminapi.Model.Type; import org.teiid.adminapi.impl.ModelMetaData; import org.teiid.cdk.api.TranslationUtility; import org.teiid.core.util.ObjectConverterUtil; import org.teiid.core.util.PropertiesUtils; import org.teiid.core.util.UnitTestUtil; import org.teiid.language.Command; import org.teiid.language.QueryExpression; import org.teiid.metadata.Column; import org.teiid.metadata.MetadataFactory; import org.teiid.metadata.Procedure; import org.teiid.query.metadata.DDLStringVisitor; import org.teiid.query.metadata.SystemMetadata; import org.teiid.query.metadata.TransformationMetadata; import org.teiid.query.unittest.RealMetadataFactory; import org.teiid.translator.ExecutionContext; import org.teiid.translator.ResultSetExecution; import org.teiid.translator.UpdateExecution; import org.teiid.translator.WSConnection; @SuppressWarnings({"nls", "unused"}) public class TestODataUpdateExecution { private String helpExecute(String query, final String resultXML, String expectedURL, int[] responseCode, int times) throws Exception { TransformationMetadata metadata = TestDataEntitySchemaBuilder.getNorthwindMetadataFromODataXML(); return helpExecute(query, resultXML, expectedURL, responseCode, metadata, times); } private String helpExecute(String query, final String resultXML, String expectedURL, int[] responseCode, TransformationMetadata metadata, int times) throws Exception { ODataExecutionFactory translator = new ODataExecutionFactory(); translator.start(); TranslationUtility utility = new TranslationUtility(metadata); Command cmd = utility.parseCommand(query); ExecutionContext context = Mockito.mock(ExecutionContext.class); WSConnection connection = Mockito.mock(WSConnection.class); Map<String, Object> headers = new HashMap<String, Object>(); headers.put(MessageContext.HTTP_REQUEST_HEADERS, new HashMap<String, List<String>>()); headers.put(WSConnection.STATUS_CODE, new Integer(responseCode[0])); Dispatch<DataSource> dispatch = Mockito.mock(Dispatch.class); Mockito.stub(dispatch.getRequestContext()).toReturn(headers); Mockito.stub(dispatch.getResponseContext()).toReturn(headers); Mockito.stub(connection.createDispatch(Mockito.eq(HTTPBinding.HTTP_BINDING), Mockito.anyString(), Mockito.eq(DataSource.class), Mockito.eq(Mode.MESSAGE))).toReturn(dispatch); DataSource ds = new DataSource() { @Override public OutputStream getOutputStream() throws IOException { return new ByteArrayOutputStream(); } @Override public String getName() { return "result"; } @Override public InputStream getInputStream() throws IOException { ByteArrayInputStream in = new ByteArrayInputStream(resultXML.getBytes()); return in; } @Override public String getContentType() { return "application/xml"; } }; ArgumentCaptor<DataSource> payload = ArgumentCaptor.forClass(DataSource.class); Mockito.stub(dispatch.invoke(payload.capture())).toReturn(ds); UpdateExecution execution = translator.createUpdateExecution(cmd, context, utility.createRuntimeMetadata(), connection); execution.execute(); ArgumentCaptor<String> endpoint = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> binding = ArgumentCaptor.forClass(String.class); Mockito.verify(connection, Mockito.times(times)).createDispatch(binding.capture(), endpoint.capture(), Mockito.eq(DataSource.class), Mockito.eq(Mode.MESSAGE)); Mockito.verify(dispatch, Mockito.times(times)).invoke(payload.capture()); assertEquals(expectedURL, URLDecoder.decode(endpoint.getValue(), "utf-8")); if (payload.getAllValues() != null) { List<DataSource> listDS = payload.getAllValues(); InputStream in = null; if (times > 1) { in = listDS.get(1).getInputStream(); } else { in = listDS.get(0).getInputStream(); } return new String(ObjectConverterUtil.convertToByteArray(in)); } return ""; } @Test public void testSimpleInsert() throws Exception { String query = "INSERT INTO Categories(CategoryID, CategoryName, Description) values(1, 'catname', 'desc')"; String expectedURL = "Categories"; FileReader reader = new FileReader(UnitTestUtil.getTestDataFile("categories.xml")); String payload = helpExecute(query, ObjectConverterUtil.convertToString(reader), expectedURL, new int[] {201, 201}, 1); reader.close(); String expected = "<category term=\"NorthwindModel.Category\" " + "scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\"></category>" + "<content type=\"application/xml\">" + "<m:properties><d:CategoryID m:type=\"Edm.Int32\">1</d:CategoryID>" + "<d:CategoryName>catname</d:CategoryName><d:Description>desc</d:Description>" + "</m:properties></content>" + "</entry>"; assertTrue(expected, payload.endsWith(expected)); } @Test public void testSimpleUpdate() throws Exception { String query = "Update Categories set CategoryName = 'catname' where CategoryID=1"; String expectedURL = "Categories(1)"; FileReader reader = new FileReader(UnitTestUtil.getTestDataFile("categories.xml")); String payload = helpExecute(query, ObjectConverterUtil.convertToString(reader), expectedURL, new int[] {200, 204}, 2); reader.close(); String expected = "<category term=\"NorthwindModel.Category\" " + "scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\">" + "</category>" + "<content type=\"application/xml\">" + "<m:properties>" + "<d:CategoryName>catname</d:CategoryName>" + "</m:properties></content>" + "</entry>"; assertTrue(expected, payload.endsWith(expected)); } @Test public void testArrayInsert() throws Exception { ModelMetaData model = new ModelMetaData(); model.setName("nw"); model.setModelType(Type.PHYSICAL); MetadataFactory mf = new MetadataFactory("northwind", 1, SystemMetadata.getInstance().getRuntimeTypeMap(), model); EdmDataServices edm = new EdmxFormatParser().parseMetadata( StaxUtil.newXMLEventReader(new FileReader(UnitTestUtil.getTestDataFile("arraytest.xml")))); ODataMetadataProcessor metadataProcessor = new ODataMetadataProcessor(); PropertiesUtils.setBeanProperties(metadataProcessor, mf.getModelProperties(), "importer"); //$NON-NLS-1$ metadataProcessor.getMetadata(mf, edm); Column c = mf.getSchema().getTable("G2").getColumnByName("e3"); assertEquals("integer[]", c.getRuntimeType()); String ddl = DDLStringVisitor.getDDLString(mf.getSchema(), null, null); TransformationMetadata metadata = RealMetadataFactory.fromDDL(ddl, "northwind", "nw"); String query = "insert into G2 (e1, e3) values(1, (1,2,3))"; String expectedURL = "G2"; String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xml:base=\"http://localhost:8080/odata/loopy/\">\n" + " <title type=\"text\">VM1.x</title>\n" + " <id>http://localhost:8080/odata/loopy/VM1.x</id>\n" + " <updated>2015-10-14T19:36:58Z</updated>\n" + " <link rel=\"self\" title=\"VM1.x\" href=\"VM1.x\" />\n" + " <entry>\n" + " <id>http://localhost:8080/odata/loopy/VM1.x('x')</id>\n" + " <title type=\"text\" />\n" + " <updated>2015-10-14T19:36:58Z</updated>\n" + " <author>\n" + " <name />\n" + " </author>\n" + " <link rel=\"edit\" title=\"x\" href=\"VM1.x('x')\" />\n" + " <category term=\"PM1.G2\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />\n" + " <content type=\"application/xml\">\n" + " <m:properties>\n" + " <d:e1>32</d:e1>\n" + " <d:e3 m:type=\"Collection(Edm.Int32)\">\n" + " <d:element>1</d:element>\n" + " <d:element>2</d:element>\n" + " <d:element>3</d:element>\n" + " </d:e3>\n" + " </m:properties>\n" + " </content>\n" + " </entry>\n" + "</feed>"; String payload = helpExecute(query, result, expectedURL, new int[] {201, 201}, metadata, 1); String expected = "<category term=\"PM1.G2\" " + "scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\">" + "</category>" + "<content type=\"application/xml\">" + "<m:properties>" + "<d:e1 m:type=\"Edm.Int32\">1</d:e1>" + "<d:e3 m:type=\"Collection(Edm.Int32)\">" + "<d:element>1</d:element>" + "<d:element>2</d:element>" + "<d:element>3</d:element>" + "</d:e3>" + "</m:properties>" + "</content>" + "</entry>"; assertTrue(expected, payload.endsWith(expected)); } @Test public void testArrayUpdate() throws Exception { ModelMetaData model = new ModelMetaData(); model.setName("nw"); model.setModelType(Type.PHYSICAL); MetadataFactory mf = new MetadataFactory("northwind", 1, SystemMetadata.getInstance().getRuntimeTypeMap(), model); EdmDataServices edm = new EdmxFormatParser().parseMetadata( StaxUtil.newXMLEventReader(new FileReader(UnitTestUtil.getTestDataFile("arraytest.xml")))); ODataMetadataProcessor metadataProcessor = new ODataMetadataProcessor(); PropertiesUtils.setBeanProperties(metadataProcessor, mf.getModelProperties(), "importer"); //$NON-NLS-1$ metadataProcessor.getMetadata(mf, edm); Column c = mf.getSchema().getTable("G2").getColumnByName("e3"); assertEquals("integer[]", c.getRuntimeType()); String ddl = DDLStringVisitor.getDDLString(mf.getSchema(), null, null); TransformationMetadata metadata = RealMetadataFactory.fromDDL(ddl, "northwind", "nw"); String query = "Update G2 set e3 = (1,2,3) where e1 = 1"; String expectedURL = "G2(1)"; String result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xml:base=\"http://localhost:8080/odata/loopy/\">\n" + " <title type=\"text\">VM1.x</title>\n" + " <id>http://localhost:8080/odata/loopy/VM1.x</id>\n" + " <updated>2015-10-14T19:36:58Z</updated>\n" + " <link rel=\"self\" title=\"VM1.x\" href=\"VM1.x\" />\n" + " <entry>\n" + " <id>http://localhost:8080/odata/loopy/VM1.x('x')</id>\n" + " <title type=\"text\" />\n" + " <updated>2015-10-14T19:36:58Z</updated>\n" + " <author>\n" + " <name />\n" + " </author>\n" + " <link rel=\"edit\" title=\"x\" href=\"VM1.x('x')\" />\n" + " <category term=\"PM1.G2\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />\n" + " <content type=\"application/xml\">\n" + " <m:properties>\n" + " <d:e1>32</d:e1>\n" + " <d:e3 m:type=\"Collection(Edm.Int32)\">\n" + " <d:element>1</d:element>\n" + " <d:element>2</d:element>\n" + " <d:element>3</d:element>\n" + " </d:e3>\n" + " </m:properties>\n" + " </content>\n" + " </entry>\n" + "</feed>"; String payload = helpExecute(query, result, expectedURL, new int[] {200, 204}, metadata, 2); String expected = "<category term=\"PM1.G2\" " + "scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\">" + "</category>" + "<content type=\"application/xml\">" + "<m:properties><d:e3 m:type=\"Collection(Edm.Int32)\">" + "<d:element>1</d:element>" + "<d:element>2</d:element>" + "<d:element>3</d:element>" + "</d:e3>" + "</m:properties>" + "</content>" + "</entry>"; assertTrue(expected, payload.endsWith(expected)); } }