/* * Copyright © 2015 Cask Data, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package co.cask.cdap.explore.service; import co.cask.cdap.api.data.schema.Schema; import co.cask.cdap.api.dataset.DatasetDefinition; import co.cask.cdap.api.dataset.lib.ObjectMappedTable; import co.cask.cdap.api.dataset.lib.ObjectMappedTableProperties; import co.cask.cdap.explore.client.ExploreExecutionResult; import co.cask.cdap.explore.service.datasets.Record; import co.cask.cdap.proto.ColumnDesc; import co.cask.cdap.proto.QueryResult; import co.cask.cdap.test.SlowTests; import co.cask.tephra.Transaction; import co.cask.tephra.TransactionAware; import com.google.common.collect.Lists; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; import java.util.List; /** * Tests exploration of object mapped tables. */ @Category(SlowTests.class) public class HiveExploreObjectMappedTableTestRun extends BaseHiveExploreServiceTest { @ClassRule public static TemporaryFolder tmpFolder = new TemporaryFolder(); private static Record record1; private static Record record2; @BeforeClass public static void start() throws Exception { initialize(tmpFolder); datasetFramework.addInstance(ObjectMappedTable.class.getName(), MY_TABLE, ObjectMappedTableProperties.builder() .setType(Record.class) .setRowKeyExploreName("row_key") .setRowKeyExploreType(Schema.Type.STRING) .build()); // Accessing dataset instance to perform data operations ObjectMappedTable<Record> table = datasetFramework.getDataset(MY_TABLE, DatasetDefinition.NO_ARGUMENTS, null); Assert.assertNotNull(table); TransactionAware txTable = (TransactionAware) table; Transaction tx1 = transactionManager.startShort(100); txTable.startTx(tx1); record1 = new Record(123, 1234567890L, 3.14159f, 3.1415926535, "foobar", new byte[] { 1, 2, 3 }); record2 = new Record(0 - 987, 9876543210L, 2.71f, 2.71112384, "hello world", new byte[] { 4, 5, 6 }); table.write("123", record1); table.write("456", record2); Assert.assertTrue(txTable.commitTx()); transactionManager.canCommit(tx1, txTable.getTxChanges()); transactionManager.commit(tx1); txTable.postTxCommit(); Transaction tx2 = transactionManager.startShort(100); txTable.startTx(tx2); } @AfterClass public static void stop() throws Exception { datasetFramework.deleteInstance(MY_TABLE); } @Test public void testSchema() throws Exception { runCommand(NAMESPACE_ID, "describe " + MY_TABLE_NAME, true, Lists.newArrayList( new ColumnDesc("col_name", "STRING", 1, "from deserializer"), new ColumnDesc("data_type", "STRING", 2, "from deserializer"), new ColumnDesc("comment", "STRING", 3, "from deserializer") ), Lists.newArrayList( new QueryResult(Lists.<Object>newArrayList("row_key", "string", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("bytearrayfield", "binary", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("doublefield", "double", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("floatfield", "float", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("intfield", "int", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("longfield", "bigint", "from deserializer")), new QueryResult(Lists.<Object>newArrayList("stringfield", "string", "from deserializer")) ) ); } @Test public void testSelectStar() throws Exception { List<ColumnDesc> expectedSchema = Lists.newArrayList( new ColumnDesc(MY_TABLE_NAME + ".row_key", "STRING", 1, null), new ColumnDesc(MY_TABLE_NAME + ".bytearrayfield", "BINARY", 2, null), new ColumnDesc(MY_TABLE_NAME + ".doublefield", "DOUBLE", 3, null), new ColumnDesc(MY_TABLE_NAME + ".floatfield", "FLOAT", 4, null), new ColumnDesc(MY_TABLE_NAME + ".intfield", "INT", 5, null), new ColumnDesc(MY_TABLE_NAME + ".longfield", "BIGINT", 6, null), new ColumnDesc(MY_TABLE_NAME + ".stringfield", "STRING", 7, null) ); ExploreExecutionResult results = exploreClient.submit(NAMESPACE_ID, "select * from " + MY_TABLE_NAME).get(); // check schema Assert.assertEquals(expectedSchema, results.getResultSchema()); List<Object> columns = results.next().getColumns(); // check record1 Assert.assertEquals("123", columns.get(0)); Assert.assertArrayEquals(record1.byteArrayField, (byte[]) columns.get(1)); Assert.assertTrue(Math.abs(record1.doubleField - (Double) columns.get(2)) < 0.000001); // sigh... why are floats returned as doubles?? Assert.assertTrue(Math.abs(record1.floatField - (Double) columns.get(3)) < 0.000001); Assert.assertEquals(record1.intField, columns.get(4)); Assert.assertEquals(record1.longField, columns.get(5)); Assert.assertEquals(record1.stringField, columns.get(6)); // check record2 columns = results.next().getColumns(); Assert.assertEquals("456", columns.get(0)); Assert.assertArrayEquals(record2.byteArrayField, (byte[]) columns.get(1)); Assert.assertTrue(Math.abs(record2.doubleField - (Double) columns.get(2)) < 0.000001); Assert.assertTrue(Math.abs(record2.floatField - (Double) columns.get(3)) < 0.000001); Assert.assertEquals(record2.intField, columns.get(4)); Assert.assertEquals(record2.longField, columns.get(5)); Assert.assertEquals(record2.stringField, columns.get(6)); // should not be any more Assert.assertFalse(results.hasNext()); } @Test public void testSelect() throws Exception { String command = String.format("select intfield, stringfield from %s where row_key='123'", MY_TABLE_NAME); runCommand(NAMESPACE_ID, command, true, Lists.newArrayList(new ColumnDesc("intfield", "INT", 1, null), new ColumnDesc("stringfield", "STRING", 2, null)), Lists.newArrayList(new QueryResult(Lists.<Object>newArrayList(record1.intField, record1.stringField))) ); } }