Skip to content

Commit

Permalink
Migrate MemSQL to use BaseCaseInsensitiveMappingTest
Browse files Browse the repository at this point in the history
  • Loading branch information
hashhar committed Mar 3, 2022
1 parent 1f19265 commit dacde64
Showing 1 changed file with 33 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,170 +15,68 @@

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.trino.testing.AbstractTestQueryFramework;
import io.trino.plugin.jdbc.BaseCaseInsensitiveMappingTest;
import io.trino.testing.QueryRunner;
import io.trino.testing.sql.TestTable;
import org.testng.annotations.AfterClass;
import io.trino.testing.sql.SqlExecutor;
import org.testng.annotations.Test;

import java.util.stream.Stream;
import java.nio.file.Path;

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static io.trino.plugin.jdbc.mapping.RuleBasedIdentifierMappingUtils.createRuleBasedIdentifierMappingFile;
import static io.trino.plugin.memsql.MemSqlQueryRunner.createMemSqlQueryRunner;
import static io.trino.testing.assertions.Assert.assertEquals;
import static java.lang.String.format;
import static java.util.Locale.ENGLISH;
import static org.assertj.core.api.Assertions.assertThat;
import static java.util.Objects.requireNonNull;

// With case-insensitive-name-matching enabled colliding schema/table names are considered as errors.
// Some tests here create colliding names which can cause any other concurrent test to fail.
@Test(singleThreaded = true)
public class TestMemSqlCaseInsensitiveMapping
// TODO extends BaseCaseInsensitiveMappingTest - https://github.com/trinodb/trino/issues/7864
extends AbstractTestQueryFramework
extends BaseCaseInsensitiveMappingTest
{
protected Path mappingFile;
protected TestingMemSqlServer memSqlServer;

@Override
protected QueryRunner createQueryRunner()
throws Exception
{
memSqlServer = new TestingMemSqlServer();
return createMemSqlQueryRunner(memSqlServer, ImmutableMap.of(), ImmutableMap.of("case-insensitive-name-matching", "true"), ImmutableList.of());
mappingFile = createRuleBasedIdentifierMappingFile();
memSqlServer = closeAfterClass(new TestingMemSqlServer());
return createMemSqlQueryRunner(
memSqlServer,
ImmutableMap.of(),
ImmutableMap.<String, String>builder()
.put("case-insensitive-name-matching", "true")
.put("case-insensitive-name-matching.config-file", mappingFile.toFile().getAbsolutePath())
.put("case-insensitive-name-matching.config-file.refresh-period", "1ms") // ~always refresh
.buildOrThrow(),
ImmutableList.of());
}

@AfterClass(alwaysRun = true)
public final void destroy()
{
memSqlServer.close();
}

@Test
public void testNonLowerCaseSchemaName()
throws Exception
@Override
protected Path getMappingFile()
{
try (AutoCloseable ignore1 = withSchema("NonLowerCaseSchema");
AutoCloseable ignore2 = withTable("NonLowerCaseSchema.lower_case_name", "(c varchar(5))");
AutoCloseable ignore3 = withTable("NonLowerCaseSchema.Mixed_Case_Name", "(c varchar(5))");
AutoCloseable ignore4 = withTable("NonLowerCaseSchema.UPPER_CASE_NAME", "(c varchar(5))")) {
assertThat(computeActual("SHOW SCHEMAS").getOnlyColumn()).contains("nonlowercaseschema");
assertQuery("SHOW SCHEMAS LIKE 'nonlowerc%'", "VALUES 'nonlowercaseschema'");
assertQuery("SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE '%nonlowercaseschema'", "VALUES 'nonlowercaseschema'");
assertQuery("SHOW TABLES FROM nonlowercaseschema", "VALUES 'lower_case_name', 'mixed_case_name', 'upper_case_name'");
assertQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'nonlowercaseschema'", "VALUES 'lower_case_name', 'mixed_case_name', 'upper_case_name'");
assertQueryReturnsEmptyResult("SELECT * FROM nonlowercaseschema.lower_case_name");
}
return requireNonNull(mappingFile, "mappingFile is null");
}

@Test
public void testNonLowerCaseTableName()
throws Exception
@Override
protected SqlExecutor onRemoteDatabase()
{
try (AutoCloseable ignore1 = withSchema("SomeSchema");
AutoCloseable ignore2 = withTable(
"SomeSchema.NonLowerCaseTable", "(lower_case_name varchar(10), Mixed_Case_Name varchar(10), UPPER_CASE_NAME varchar(10))")) {
execute("INSERT INTO SomeSchema.NonLowerCaseTable VALUES ('a', 'b', 'c')");

assertQuery(
"SELECT column_name FROM information_schema.columns WHERE table_schema = 'someschema' AND table_name = 'nonlowercasetable'",
"VALUES 'lower_case_name', 'mixed_case_name', 'upper_case_name'");
assertQuery(
"SELECT column_name FROM information_schema.columns WHERE table_name = 'nonlowercasetable'",
"VALUES 'lower_case_name', 'mixed_case_name', 'upper_case_name'");
assertEquals(
computeActual("SHOW COLUMNS FROM someschema.nonlowercasetable").getMaterializedRows().stream()
.map(row -> row.getField(0))
.collect(toImmutableSet()),
ImmutableSet.of("lower_case_name", "mixed_case_name", "upper_case_name"));

// Note: until https://github.com/prestodb/presto/issues/2863 is resolved, this is *the* way to access the tables.

assertQuery("SELECT lower_case_name FROM someschema.nonlowercasetable", "VALUES 'a'");
assertQuery("SELECT mixed_case_name FROM someschema.nonlowercasetable", "VALUES 'b'");
assertQuery("SELECT upper_case_name FROM someschema.nonlowercasetable", "VALUES 'c'");
assertQuery("SELECT upper_case_name FROM SomeSchema.NonLowerCaseTable", "VALUES 'c'");
assertQuery("SELECT upper_case_name FROM \"SomeSchema\".\"NonLowerCaseTable\"", "VALUES 'c'");

assertUpdate("INSERT INTO someschema.nonlowercasetable (lower_case_name) VALUES ('lower')", 1);
assertUpdate("INSERT INTO someschema.nonlowercasetable (mixed_case_name) VALUES ('mixed')", 1);
assertUpdate("INSERT INTO someschema.nonlowercasetable (upper_case_name) VALUES ('upper')", 1);
assertQuery(
"SELECT * FROM someschema.nonlowercasetable",
"VALUES ('a', 'b', 'c')," +
"('lower', NULL, NULL)," +
"(NULL, 'mixed', NULL)," +
"(NULL, NULL, 'upper')");
}
return requireNonNull(memSqlServer, "memSqlServer is null")::execute;
}

@Test
public void testSchemaNameClash()
throws Exception
@Override
protected String quoted(String name)
{
String[] nameVariants = {"casesensitivename", "CaseSensitiveName", "CASESENSITIVENAME"};
assertThat(Stream.of(nameVariants)
.map(name -> name.toLowerCase(ENGLISH))
.collect(toImmutableSet()))
.hasSize(1);

for (int i = 0; i < nameVariants.length; i++) {
for (int j = i + 1; j < nameVariants.length; j++) {
String schemaName = nameVariants[i];
String otherSchemaName = nameVariants[j];
try (AutoCloseable ignore1 = withSchema(schemaName);
AutoCloseable ignore2 = withSchema(otherSchemaName);
AutoCloseable ignore3 = withTable(schemaName + ".some_table_name", "(c varchar(5))")) {
assertThat(computeActual("SHOW SCHEMAS").getOnlyColumn()).contains("casesensitivename");
assertThat(computeActual("SHOW SCHEMAS").getOnlyColumn().filter("casesensitivename"::equals)).hasSize(1); // TODO change io.trino.plugin.jdbc.JdbcClient.getSchemaNames to return a List
assertQueryFails("SHOW TABLES FROM casesensitivename", "Failed to find remote schema name: Ambiguous name: casesensitivename");
assertQueryFails("SELECT * FROM casesensitivename.some_table_name", "Failed to find remote schema name: Ambiguous name: casesensitivename");
}
}
}
String identifierQuote = "`";
name = name.replace(identifierQuote, identifierQuote + identifierQuote);
return identifierQuote + name + identifierQuote;
}

@Test
public void testTableNameClash()
throws Exception
{
String[] nameVariants = {"casesensitivename", "CaseSensitiveName", "CASESENSITIVENAME"};
assertThat(Stream.of(nameVariants)
.map(name -> name.toLowerCase(ENGLISH))
.collect(toImmutableSet()))
.hasSize(1);

for (int i = 0; i < nameVariants.length; i++) {
for (int j = i + 1; j < nameVariants.length; j++) {
try (AutoCloseable ignore1 = withTable("tpch." + nameVariants[i], "(c varchar(5))");
AutoCloseable ignore2 = withTable("tpch." + nameVariants[j], "(d varchar(5))")) {
assertThat(computeActual("SHOW TABLES").getOnlyColumn()).contains("casesensitivename");
assertThat(computeActual("SHOW TABLES").getOnlyColumn().filter("casesensitivename"::equals)).hasSize(1); // TODO, should be 2
assertQueryFails("SHOW COLUMNS FROM casesensitivename", "Failed to find remote table name: Ambiguous name: casesensitivename");
assertQueryFails("SELECT * FROM casesensitivename", "Failed to find remote table name: Ambiguous name: casesensitivename");
}
}
}
}

private AutoCloseable withSchema(String schemaName)
{
execute(format("CREATE SCHEMA `%s`", schemaName));
return () -> execute(format("DROP SCHEMA `%s`", schemaName));
}

/**
* @deprecated Use {@link TestTable} instead.
*/
@Deprecated
private AutoCloseable withTable(String tableName, String tableDefinition)
{
execute(format("CREATE TABLE %s %s", tableName, tableDefinition));
return () -> execute(format("DROP TABLE %s", tableName));
}

private void execute(String sql)
public void forceTestNgToRespectSingleThreaded()
{
memSqlServer.execute(sql);
// TODO: Remove after updating TestNG to 7.4.0+ (https://github.com/trinodb/trino/issues/8571)
// TestNG doesn't enforce @Test(singleThreaded = true) when tests are defined in base class. According to
// https://github.com/cbeust/testng/issues/2361#issuecomment-688393166 a workaround it to add a dummy test to the leaf test class.
}
}

0 comments on commit dacde64

Please sign in to comment.