Repository: cassandra
Updated Branches:
  refs/heads/trunk 3b6c93828 -> 0d464cd25


http://git-wip-us.apache.org/repos/asf/cassandra/blob/0d464cd2/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java
new file mode 100644
index 0000000..3581a73
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.validation.entities;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.db.Mutation;
+import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.db.partitions.Partition;
+import org.apache.cassandra.db.partitions.PartitionUpdate;
+import org.apache.cassandra.db.virtual.AbstractVirtualTable;
+import org.apache.cassandra.db.virtual.SimpleDataSet;
+import org.apache.cassandra.db.virtual.VirtualKeyspace;
+import org.apache.cassandra.db.virtual.VirtualKeyspaceRegistry;
+import org.apache.cassandra.db.virtual.VirtualTable;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.service.StorageServiceMBean;
+import org.apache.cassandra.triggers.ITrigger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class VirtualTableTest extends CQLTester
+{
+    private static final String KS_NAME = "test_virtual_ks";
+    private static final String VT1_NAME = "vt1";
+    private static final String VT2_NAME = "vt2";
+
+    private static class WritableVirtualTable extends AbstractVirtualTable
+    {
+        private final ColumnMetadata valueColumn;
+        private final Map<String, Integer> backingMap = new HashMap<>();
+
+        WritableVirtualTable(String keyspaceName, String tableName)
+        {
+            super(TableMetadata.builder(keyspaceName, tableName)
+                               .kind(TableMetadata.Kind.VIRTUAL)
+                               .addPartitionKeyColumn("key", UTF8Type.instance)
+                               .addRegularColumn("value", Int32Type.instance)
+                               .build());
+            valueColumn = metadata().regularColumns().getSimple(0);
+        }
+
+        @Override
+        public DataSet data()
+        {
+            SimpleDataSet data = new SimpleDataSet(metadata());
+            backingMap.forEach((key, value) -> data.row(key).column("value", 
value));
+            return data;
+        }
+
+        @Override
+        public void apply(PartitionUpdate update)
+        {
+            String key = (String) 
metadata().partitionKeyType.compose(update.partitionKey().getKey());
+            update.forEach(row ->
+            {
+                Integer value = 
Int32Type.instance.compose(row.getCell(valueColumn).value());
+                backingMap.put(key, value);
+            });
+        }
+    }
+
+    @BeforeClass
+    public static void setUpClass()
+    {
+        TableMetadata vt1Metadata =
+            TableMetadata.builder(KS_NAME, VT1_NAME)
+                         .kind(TableMetadata.Kind.VIRTUAL)
+                         .addPartitionKeyColumn("pk", UTF8Type.instance)
+                         .addClusteringColumn("c", UTF8Type.instance)
+                         .addRegularColumn("v1", Int32Type.instance)
+                         .addRegularColumn("v2", LongType.instance)
+                         .build();
+
+        SimpleDataSet vt1data = new SimpleDataSet(vt1Metadata);
+
+        vt1data.row("pk1", "c1").column("v1", 11).column("v2", 11L)
+               .row("pk2", "c1").column("v1", 21).column("v2", 21L)
+               .row("pk1", "c2").column("v1", 12).column("v2", 12L)
+               .row("pk2", "c2").column("v1", 22).column("v2", 22L)
+               .row("pk1", "c3").column("v1", 13).column("v2", 13L)
+               .row("pk2", "c3").column("v1", 23).column("v2", 23L);
+
+        VirtualTable vt1 = new AbstractVirtualTable(vt1Metadata)
+        {
+            public DataSet data()
+            {
+                return vt1data;
+            }
+        };
+        VirtualTable vt2 = new WritableVirtualTable(KS_NAME, VT2_NAME);
+
+        VirtualKeyspaceRegistry.instance.register(new VirtualKeyspace(KS_NAME, 
ImmutableList.of(vt1, vt2)));
+
+        CQLTester.setUpClass();
+    }
+
+    @Test
+    public void testQueries() throws Throwable
+    {
+        assertRowsNet(executeNet("SELECT * FROM test_virtual_ks.vt1 WHERE pk = 
'UNKNOWN'"));
+
+        assertRowsNet(executeNet("SELECT * FROM test_virtual_ks.vt1 WHERE pk = 
'pk1' AND c = 'UNKNOWN'"));
+
+        // Test DISTINCT query
+        assertRowsNet(executeNet("SELECT DISTINCT pk FROM 
test_virtual_ks.vt1"),
+                      row("pk1"),
+                      row("pk2"));
+
+        assertRowsNet(executeNet("SELECT DISTINCT pk FROM test_virtual_ks.vt1 
WHERE token(pk) > token('pk1')"),
+                      row("pk2"));
+
+        // Test single partition queries
+        assertRowsNet(executeNet("SELECT v1, v2 FROM test_virtual_ks.vt1 WHERE 
pk = 'pk1' AND c = 'c1'"),
+                      row(11, 11L));
+
+        assertRowsNet(executeNet("SELECT c, v1, v2 FROM test_virtual_ks.vt1 
WHERE pk = 'pk1' AND c IN ('c1', 'c2')"),
+                      row("c1", 11, 11L),
+                      row("c2", 12, 12L));
+
+        assertRowsNet(executeNet("SELECT c, v1, v2 FROM test_virtual_ks.vt1 
WHERE pk = 'pk1' AND c IN ('c2', 'c1') ORDER BY c DESC"),
+                      row("c2", 12, 12L),
+                      row("c1", 11, 11L));
+
+        // Test multi-partition queries
+        assertRows(execute("SELECT * FROM test_virtual_ks.vt1 WHERE pk IN 
('pk2', 'pk1') AND c IN ('c2', 'c1')"),
+                   row("pk1", "c1", 11, 11L),
+                   row("pk1", "c2", 12, 12L),
+                   row("pk2", "c1", 21, 21L),
+                   row("pk2", "c2", 22, 22L));
+
+        assertRows(execute("SELECT pk, c, v1 FROM test_virtual_ks.vt1 WHERE pk 
IN ('pk2', 'pk1') AND c IN ('c2', 'c1') ORDER BY c DESC"),
+                   row("pk1", "c2", 12),
+                   row("pk2", "c2", 22),
+                   row("pk1", "c1", 11),
+                   row("pk2", "c1", 21));
+
+        assertRows(execute("SELECT pk, c, v1 FROM test_virtual_ks.vt1 WHERE pk 
IN ('pk2', 'pk1') AND c IN ('c2', 'c1') ORDER BY c DESC LIMIT 1"),
+                   row("pk1", "c2", 12));
+
+        assertRows(execute("SELECT c, v1, v2 FROM test_virtual_ks.vt1 WHERE pk 
IN ('pk2', 'pk1') AND c IN ('c2', 'c1' , 'c3') ORDER BY c DESC PER PARTITION 
LIMIT 1"),
+                   row("c3", 13, 13L),
+                   row("c3", 23, 23L));
+
+        assertRows(execute("SELECT count(*) FROM test_virtual_ks.vt1 WHERE pk 
IN ('pk2', 'pk1') AND c IN ('c2', 'c1')"),
+                   row(4L));
+
+        for (int pageSize = 1; pageSize < 5; pageSize++)
+        {
+            assertRowsNet(executeNetWithPaging("SELECT pk, c, v1, v2 FROM 
test_virtual_ks.vt1 WHERE pk IN ('pk2', 'pk1') AND c IN ('c2', 'c1')", 
pageSize),
+                          row("pk1", "c1", 11, 11L),
+                          row("pk1", "c2", 12, 12L),
+                          row("pk2", "c1", 21, 21L),
+                          row("pk2", "c2", 22, 22L));
+
+            assertRowsNet(executeNetWithPaging("SELECT * FROM 
test_virtual_ks.vt1 WHERE pk IN ('pk2', 'pk1') AND c IN ('c2', 'c1') LIMIT 2", 
pageSize),
+                          row("pk1", "c1", 11, 11L),
+                          row("pk1", "c2", 12, 12L));
+
+            assertRowsNet(executeNetWithPaging("SELECT count(*) FROM 
test_virtual_ks.vt1 WHERE pk IN ('pk2', 'pk1') AND c IN ('c2', 'c1')", 
pageSize),
+                          row(4L));
+        }
+
+        // Test range queries
+        for (int pageSize = 1; pageSize < 4; pageSize++)
+        {
+            assertRowsNet(executeNetWithPaging("SELECT * FROM 
test_virtual_ks.vt1 WHERE token(pk) < token('pk2') AND c IN ('c2', 'c1') ALLOW 
FILTERING", pageSize),
+                          row("pk1", "c1", 11, 11L),
+                          row("pk1", "c2", 12, 12L));
+
+            assertRowsNet(executeNetWithPaging("SELECT * FROM 
test_virtual_ks.vt1 WHERE token(pk) < token('pk2') AND c IN ('c2', 'c1') LIMIT 
1 ALLOW FILTERING", pageSize),
+                          row("pk1", "c1", 11, 11L));
+
+            assertRowsNet(executeNetWithPaging("SELECT * FROM 
test_virtual_ks.vt1 WHERE token(pk) <= token('pk2') AND c > 'c1' PER PARTITION 
LIMIT 1 ALLOW FILTERING", pageSize),
+                          row("pk1", "c2", 12, 12L),
+                          row("pk2", "c2", 22, 22L));
+
+            assertRowsNet(executeNetWithPaging("SELECT count(*) FROM 
test_virtual_ks.vt1 WHERE token(pk) = token('pk2') AND c < 'c3' ALLOW 
FILTERING", pageSize),
+                          row(2L));
+        }
+    }
+
+    @Test
+    public void testModifications() throws Throwable
+    {
+        // check for clean state
+        assertRows(execute("SELECT * FROM test_virtual_ks.vt2"));
+
+        // fill the table, test UNLOGGED batch
+        execute("BEGIN UNLOGGED BATCH " +
+                "UPDATE test_virtual_ks.vt2 SET value = 1 WHERE key ='pk1';" +
+                "UPDATE test_virtual_ks.vt2 SET value = 2 WHERE key ='pk2';" +
+                "UPDATE test_virtual_ks.vt2 SET value = 3 WHERE key ='pk3';" +
+                "APPLY BATCH");
+        assertRows(execute("SELECT * FROM test_virtual_ks.vt2"),
+                   row("pk1", 1),
+                   row("pk2", 2),
+                   row("pk3", 3));
+
+        // test that LOGGED batches don't allow virtual table updates
+        assertInvalidMessage("Cannot include a virtual table statement in a 
logged batch",
+                             "BEGIN BATCH " +
+                             "UPDATE test_virtual_ks.vt2 SET value = 1 WHERE 
key ='pk1';" +
+                             "UPDATE test_virtual_ks.vt2 SET value = 2 WHERE 
key ='pk2';" +
+                             "UPDATE test_virtual_ks.vt2 SET value = 3 WHERE 
key ='pk3';" +
+                             "APPLY BATCH");
+
+        // test that UNLOGGED batch doesn't allow mixing updates for regular 
and virtual tables
+        createTable("CREATE TABLE %s (key text PRIMARY KEY, value int)");
+        assertInvalidMessage("Mutations for virtual and regular tables cannot 
exist in the same batch",
+                             "BEGIN UNLOGGED BATCH " +
+                             "UPDATE test_virtual_ks.vt2 SET value = 1 WHERE 
key ='pk1'" +
+                             "UPDATE %s                  SET value = 2 WHERE 
key ='pk2'" +
+                             "UPDATE test_virtual_ks.vt2 SET value = 3 WHERE 
key ='pk3'" +
+                             "APPLY BATCH");
+
+        // update a single value with UPDATE
+        execute("UPDATE test_virtual_ks.vt2 SET value = 11 WHERE key ='pk1'");
+        assertRows(execute("SELECT * FROM test_virtual_ks.vt2 WHERE key = 
'pk1'"),
+                   row("pk1", 11));
+
+        // update a single value with INSERT
+        executeNet("INSERT INTO test_virtual_ks.vt2 (key, value) VALUES 
('pk2', 22)");
+        assertRows(execute("SELECT * FROM test_virtual_ks.vt2 WHERE key = 
'pk2'"),
+                   row("pk2", 22));
+
+        // test that deletions are (currently) rejected
+        assertInvalidMessage("Virtual tables don't support DELETE statements",
+                             "DELETE FROM test_virtual_ks.vt2 WHERE key 
='pk1'");
+
+        // test that TTL is (currently) rejected with INSERT and UPDATE
+        assertInvalidMessage("Expiring columns are not supported by virtual 
tables",
+                             "INSERT INTO test_virtual_ks.vt2 (key, value) 
VALUES ('pk1', 11) USING TTL 86400");
+        assertInvalidMessage("Expiring columns are not supported by virtual 
tables",
+                             "UPDATE test_virtual_ks.vt2 USING TTL 86400 SET 
value = 11 WHERE key ='pk1'");
+
+        // test that LWT is (currently) rejected with virtual tables in batches
+        assertInvalidMessage("Conditional BATCH statements cannot include 
mutations for virtual tables",
+                             "BEGIN UNLOGGED BATCH " +
+                             "UPDATE test_virtual_ks.vt2 SET value = 3 WHERE 
key ='pk3' IF value = 2;" +
+                             "APPLY BATCH");
+
+        // test that LWT is (currently) rejected with virtual tables in UPDATEs
+        assertInvalidMessage("Conditional updates are not supported by virtual 
tables",
+                             "UPDATE test_virtual_ks.vt2 SET value = 3 WHERE 
key ='pk3' IF value = 2");
+
+        // test that LWT is (currently) rejected with virtual tables in INSERTs
+        assertInvalidMessage("Conditional updates are not supported by virtual 
tables",
+                             "INSERT INTO test_virtual_ks.vt2 (key, value) 
VALUES ('pk2', 22) IF NOT EXISTS");
+    }
+
+    @Test
+    public void testInvalidDDLOperations() throws Throwable
+    {
+        assertInvalidMessage("Cannot drop virtual keyspaces",
+                             "DROP KEYSPACE test_virtual_ks");
+
+        assertInvalidMessage("Cannot alter virtual keyspaces",
+                             "ALTER KEYSPACE test_virtual_ks WITH 
durable_writes = false");
+
+        assertInvalidMessage("Cannot create tables in virtual keyspaces",
+                             "CREATE TABLE test_virtual_ks.test (id int 
PRIMARY KEY)");
+
+        assertInvalidMessage("Cannot create types in virtual keyspaces",
+                             "CREATE TYPE test_virtual_ks.type (id int)");
+
+        assertInvalidMessage("Cannot drop virtual tables",
+                             "DROP TABLE test_virtual_ks.vt1");
+
+        assertInvalidMessage("Cannot alter virtual tables",
+                             "ALTER TABLE test_virtual_ks.vt1 DROP v1");
+
+        assertInvalidMessage("Cannot truncate virtual tables",
+                             "TRUNCATE TABLE test_virtual_ks.vt1");
+
+        assertInvalidMessage("Secondary indexes are not supported on virtual 
tables",
+                             "CREATE INDEX ON test_virtual_ks.vt1 (v1)");
+
+        assertInvalidMessage("Materialized views are not supported on virtual 
tables",
+                             "CREATE MATERIALIZED VIEW test_virtual_ks.mvt1 AS 
SELECT c, v1 FROM test_virtual_ks.vt1 WHERE c IS NOT NULL PRIMARY KEY(c)");
+
+        assertInvalidMessage("Cannot CREATE TRIGGER against a virtual table",
+                             "CREATE TRIGGER test_trigger ON 
test_virtual_ks.vt1 USING '" + TestTrigger.class.getName() + '\'');
+    }
+
+    /**
+     * Noop trigger for audit log testing
+     */
+    public static class TestTrigger implements ITrigger
+    {
+        public Collection<Mutation> augment(Partition update)
+        {
+            return null;
+        }
+    }
+
+    @Test
+    public void testMBeansMethods() throws Throwable
+    {
+        StorageServiceMBean mbean = StorageService.instance;
+
+        assertJMXFails(() -> mbean.forceKeyspaceCompaction(false, KS_NAME));
+        assertJMXFails(() -> mbean.forceKeyspaceCompaction(false, KS_NAME, 
VT1_NAME));
+
+        assertJMXFails(() -> mbean.scrub(true, true, true, true, 1, KS_NAME));
+        assertJMXFails(() -> mbean.scrub(true, true, true, true, 1, KS_NAME, 
VT1_NAME));
+
+        assertJMXFails(() -> mbean.verify(true, KS_NAME));
+        assertJMXFails(() -> mbean.verify(true, KS_NAME, VT1_NAME));
+
+        assertJMXFails(() -> mbean.upgradeSSTables(KS_NAME, false, 1));
+        assertJMXFails(() -> mbean.upgradeSSTables(KS_NAME, false, 1, 
VT1_NAME));
+
+        assertJMXFails(() -> mbean.garbageCollect("ROW", 1, KS_NAME, 
VT1_NAME));
+
+        assertJMXFails(() -> mbean.forceKeyspaceFlush(KS_NAME));
+        assertJMXFails(() -> mbean.forceKeyspaceFlush(KS_NAME, VT1_NAME));
+
+        assertJMXFails(() -> mbean.truncate(KS_NAME, VT1_NAME));
+
+        assertJMXFails(() -> mbean.loadNewSSTables(KS_NAME, VT1_NAME));
+
+        assertJMXFails(() -> mbean.getAutoCompactionStatus(KS_NAME));
+        assertJMXFails(() -> mbean.getAutoCompactionStatus(KS_NAME, VT1_NAME));
+    }
+
+    @FunctionalInterface
+    private static interface ThrowingRunnable
+    {
+        public void run() throws Throwable;
+    }
+
+    private void assertJMXFails(ThrowingRunnable r) throws Throwable
+    {
+        try
+        {
+            r.run();
+            fail();
+        }
+        catch (IllegalArgumentException e)
+        {
+            assertEquals("Cannot perform any operations against virtual 
keyspace " + KS_NAME, e.getMessage());
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to