package com.tesora.dve.sql; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ // NOPMD by doug on 04/12/12 12:05 PM import static org.junit.Assert.fail; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import com.tesora.dve.common.catalog.TemplateMode; import com.tesora.dve.distribution.BroadcastDistributionModel; import com.tesora.dve.distribution.RandomDistributionModel; import com.tesora.dve.distribution.RangeDistributionModel; import com.tesora.dve.errmap.InternalErrors; import com.tesora.dve.server.bootstrap.BootstrapHost; import com.tesora.dve.sql.template.TemplateBuilder; import com.tesora.dve.sql.template.jaxb.FkModeType; import com.tesora.dve.sql.util.PEDDL; import com.tesora.dve.sql.util.ProjectDDL; import com.tesora.dve.sql.util.ProxyConnectionResource; import com.tesora.dve.sql.util.StorageGroupDDL; import com.tesora.dve.standalone.PETest; public class MetadataInjectionTest extends SchemaTest { // only one site for this test private static final int SITES = 1; private static final ProjectDDL testDDL = new PEDDL("mitdb", new StorageGroupDDL("mit",SITES,"mitg"),"schema"); @BeforeClass public static void setup() throws Exception { PETest.projectSetup(testDDL); PETest.bootHost = BootstrapHost.startServices(PETest.class); } ProxyConnectionResource conn = null; @Before public void before() throws Throwable { conn = new ProxyConnectionResource(); testDDL.clearCreated(); testDDL.create(conn); conn.execute("drop database mitdb"); } @After public void after() throws Throwable { testDDL.destroy(conn); if(conn != null) { conn.execute("drop template if exists mit"); conn.disconnect(); } conn = null; } @Test public void testInjection() throws Throwable { // ok, let's start by ensuring the range doesn't exist yet conn.assertResults("show ranges like 'openrange'",br()); conn.execute(new TemplateBuilder("mit") .withRequirement("create range openrange (int) persistent group #sg#") .withRequirement("create range closedrange (int) persistent group #sg#") .withRangeTable("laws","openrange","id") .toCreateStatement()); conn.execute("create database mitdb default persistent group mitg using template mit strict"); conn.assertResults("select template, template_mode from information_schema.schemata where schema_name = 'mitdb'", br(nr, "mit", "STRICT")); conn.assertResults("show ranges like 'openrange'",br(nr,"openrange",testDDL.getPersistentGroup().getName(),"int")); conn.assertResults("show ranges like 'closedrange'",br(nr,"closedrange",testDDL.getPersistentGroup().getName(),"int")); // set the database on the connection conn.execute("use mitdb"); // create the table - this should pass conn.execute("create table `laws` (`id` int auto_increment, `law` longtext)"); conn.assertResults("select model_type, model_name from information_schema.distributions where database_name = 'mitdb' and table_name = 'laws'", br(nr,RangeDistributionModel.MODEL_NAME,"openrange")); // strict template should cause failure on missing template new ExpectedSqlErrorTester() { @Override public void test() throws Throwable { conn.execute("create table `titles` (`id` int auto_increment, `name` varchar(50))"); } }.assertError(SchemaException.class, InternalErrors.internalFormatter, "Internal error: No matching template found for table `titles`"); conn.execute("drop database mitdb"); // set the template conn.execute(new TemplateBuilder("mit") .withRangeTable("laws","longrange","id").toAlterStatement()); conn.execute("create database mitdb default persistent group mitg using template mit strict"); // set the database on the connection conn.execute("use mitdb"); // missing range should be caught new ExpectedSqlErrorTester() { @Override public void test() throws Throwable { conn.execute("create table `laws` (`id` int auto_increment, `law` longtext)"); } }.assertError(SchemaException.class, InternalErrors.internalFormatter, "Internal error: No such range from template 'mit' on storage group mitg: longrange"); conn.execute("drop database mitdb"); // set the template again, this time with a regex conn.execute(new TemplateBuilder("mit") .withRequirement("create range longrange (int) persistent group #sg#") .withRangeTable(".*_laws","longrange","id") .toAlterStatement()); conn.execute("create database mitdb default persistent group mitg using template mit strict"); conn.execute("use mitdb"); conn.execute("create table `lefty_laws` (`id` int auto_increment, `law` longtext)"); conn.assertResults("select model_type, model_name from information_schema.distributions where database_name = 'mitdb' and table_name = 'lefty_laws'", br(nr,RangeDistributionModel.MODEL_NAME,"longrange")); conn.execute("drop database mitdb"); conn.execute("create database mitdb default persistent group mitg using template mit"); conn.execute("use mitdb"); conn.execute("create table `righty_lawyers`(`id` int auto_increment, `law` longtext)"); conn.assertResults("select model_type from information_schema.distributions where database_name = 'mitdb' and table_name = 'righty_lawyers'", br(nr,RandomDistributionModel.MODEL_NAME)); } @Test public void testDefaultBroadcast() throws Throwable { conn.execute(new TemplateBuilder("mit") .withRequirement("create range openrange (int) persistent group #sg#") .withRequirement("create range closedrange (int) persistent group #sg#") .withRangeTable(".*cache", "openrange", "id") .withRangeTable(".*states", "openrange", "id") .withTable(".*", BroadcastDistributionModel.MODEL_NAME) .toCreateStatement()); conn.execute("create database mitdb default persistent group mitg using template mit strict"); conn.execute("use mitdb"); conn.execute("create table `should_match_cache` (`id` int auto_increment, `law` longtext)"); conn.execute("create table `no_match_at_all` (`id` int auto_increment, `law` longtext)"); conn.assertResults("select model_type, model_name from information_schema.distributions where database_name = 'mitdb' and table_name = 'should_match_cache'", br(nr,RangeDistributionModel.MODEL_NAME,"openrange")); conn.assertResults("select model_type from information_schema.distributions where database_name = 'mitdb' and table_name = 'no_match_at_all'", br(nr,BroadcastDistributionModel.MODEL_NAME)); } @Test public void testFKModeInjection() throws Throwable { conn.execute(new TemplateBuilder("mit") .withFKMode(FkModeType.IGNORE) .withTable(".*", BroadcastDistributionModel.MODEL_NAME) .toCreateStatement()); conn.execute("create database mitdb default persistent group mitg using template mit strict"); conn.assertResults("select * from information_schema.schemata where schema_name = 'mitdb'", br(nr, "def", "mitdb", "mitg", "mit", "STRICT", "off", "ignore", "utf8", "utf8_general_ci")); } @Test public void testAdditionalFields() throws Throwable { TemplateBuilder tb = new TemplateBuilder("mit").withTable(".*", BroadcastDistributionModel.MODEL_NAME); String basic = tb.toCreateStatement(); conn.execute(basic + " match='mit*' comment='test comment'"); conn.assertResults("select dbmatch, template_comment from information_schema.templates where name = 'mit'", br(nr,"mit*","test comment")); conn.execute("alter template mit set comment = 'new comment'"); conn.assertResults("select dbmatch, template_comment from information_schema.templates where name = 'mit'", br(nr,"mit*","new comment")); conn.execute("alter template mit set match='mitdb' comment='exact match'"); conn.assertResults("select dbmatch, template_comment from information_schema.templates where name = 'mit'", br(nr,"mitdb","exact match")); conn.execute("create database mitdb default persistent group mitg"); conn.assertResults("select template, template_mode from information_schema.schemata where schema_name = 'mitdb'", br(nr, "mit", TemplateMode.getCurrentDefault().toString())); } @Test public void testRangeScoping() throws Throwable { TemplateBuilder tb = new TemplateBuilder("rst") .withRequirement("create range openrange (int) persistent group #sg#") .withRangeTable(".*cache", "openrange", "id"); conn.execute(tb.toCreateStatement()); try { conn.execute("create persistent group ga add mit0"); conn.execute("create persistent group gb add mit0"); conn.execute("create database dba default persistent group ga using template rst"); conn.assertResults("show ranges", br(nr,"openrange","ga","int")); conn.execute("create database dbb default persistent group gb using template rst"); conn.assertResults("show ranges", br(nr,"openrange","ga","int", nr, "openrange","gb","int")); try { conn.execute("drop persistent group ga"); fail("shouldn't be able to drop the group - has a db"); } catch (Throwable t) { SchemaTest.assertSchemaException(t, "Unable to drop persistent group ga because used by database dba"); } conn.execute("drop database dba"); conn.execute("drop persistent group ga"); conn.execute("create persistent group ga add mit0"); conn.execute("create database dba default persistent group ga using template rst"); conn.execute("drop database dba"); try { conn.execute("drop range openrange"); fail("ambiguous, shouldn't be able to drop"); } catch (Throwable t) { SchemaTest.assertSchemaException(t, "More than one range named openrange please specify group (add persistent group <name>)"); } conn.execute("drop range openrange persistent group ga"); } finally { conn.execute("drop database if exists dba"); conn.execute("drop database if exists dbb"); conn.execute("drop persistent group ga"); conn.execute("drop persistent group gb"); } } }