Skip to content
Permalink
Browse files
[refactor](test) Refactor FE unit test framework that starts a FE ser…
…ver. (#9388)

Currently, we use `UtFrameUtils` to start a FE server in the FE unit test. 
Each test class has to do some initialization and clean up stuff with the JUnit4
`@BeforeClass` and `@AfterClass` annotation. It's redundant and boring.
Besides, almost all the APIs in `UtFrameUtils` has a `ConnectContext` parameter, which is not easy to use.

This PR proposes to use an inherit-manner, i.e., wrap all the common logic in base class `TestWithFeService`,
leveraging the 
JUnit5 `@BeforeAll` and `@AfterAll` annotation to narrow down the setup and cleanup lifecycle to each test class instance.
At the same time, the derived concrete test class could directly use utility methods inherited from the base class,
without calling a util class and passing a `ConnectContext` argument.

`UtFrameUtils` and `DorisAssert`  are marked as deprecated. We could remove these two classes
if this refactor works well for a time.
  • Loading branch information
wangshuo128 committed May 7, 2022
1 parent fd11a6b commit 1746f6138857ef63f8d714de4073a442d36ef934
Showing 18 changed files with 898 additions and 673 deletions.
@@ -79,10 +79,18 @@ under the License.
<artifactId>jmockit</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.vintage/junit-vintage-engine -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -220,11 +220,25 @@ under the License.
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<!-- https://mvnrepository.com/artifact/org.junit.vintage/junit-vintage-engine -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
@@ -20,54 +20,37 @@
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.utframe.UtFrameUtils;
import org.apache.doris.utframe.TestWithFeService;

import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.jupiter.api.Test;

import java.util.UUID;

public class AdminSetConfigStmtTest {
private static String runningDir = "fe/mocked/AdminSetConfigStmtTest/" + UUID.randomUUID().toString() + "/";

private static ConnectContext connectContext;

@Rule
public ExpectedException expectedEx = ExpectedException.none();

@BeforeClass
public static void beforeClass() throws Exception {
UtFrameUtils.createDorisCluster(runningDir);

// create connect context
connectContext = UtFrameUtils.createDefaultCtx();
}
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class AdminSetConfigStmtTest extends TestWithFeService {
@Test
public void testNormal() throws Exception {
String stmt = "admin set frontend config(\"alter_table_timeout_second\" = \"60\");";
AdminSetConfigStmt adminSetConfigStmt = (AdminSetConfigStmt) UtFrameUtils.parseAndAnalyzeStmt(stmt, connectContext);
AdminSetConfigStmt adminSetConfigStmt = (AdminSetConfigStmt) parseAndAnalyzeStmt(stmt);
Catalog.getCurrentCatalog().setConfig(adminSetConfigStmt);
}

@Test
public void testUnknownConfig() throws Exception {
String stmt = "admin set frontend config(\"unknown_config\" = \"unknown\");";
AdminSetConfigStmt adminSetConfigStmt = (AdminSetConfigStmt) UtFrameUtils.parseAndAnalyzeStmt(stmt, connectContext);
expectedEx.expect(DdlException.class);
expectedEx.expectMessage("errCode = 2, detailMessage = Config 'unknown_config' does not exist");
Catalog.getCurrentCatalog().setConfig(adminSetConfigStmt);
AdminSetConfigStmt adminSetConfigStmt = (AdminSetConfigStmt) parseAndAnalyzeStmt(stmt);
DdlException exception = assertThrows(DdlException.class,
() -> Catalog.getCurrentCatalog().setConfig(adminSetConfigStmt));
assertEquals("errCode = 2, detailMessage = Config 'unknown_config' does not exist",
exception.getMessage());
}

@Test
public void testEmptyConfig() throws Exception {
String stmt = "admin set frontend config;";
expectedEx.expect(AnalysisException.class);
expectedEx.expectMessage("errCode = 2, detailMessage = config parameter size is not equal to 1");
AdminSetConfigStmt adminSetConfigStmt = (AdminSetConfigStmt) UtFrameUtils.parseAndAnalyzeStmt(stmt, connectContext);
public void testEmptyConfig() {
AnalysisException exception =
assertThrows(AnalysisException.class,
() -> parseAndAnalyzeStmt("admin set frontend config;"));
assertEquals("errCode = 2, detailMessage = config parameter size is not equal to 1",
exception.getMessage());
}
}

@@ -25,76 +25,43 @@
import org.apache.doris.catalog.Replica;
import org.apache.doris.catalog.Tablet;
import org.apache.doris.common.util.SqlParserUtils;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowExecutor;
import org.apache.doris.qe.ShowResultSet;
import org.apache.doris.utframe.UtFrameUtils;
import org.apache.doris.utframe.TestWithFeService;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.UUID;

public class AdminShowReplicaTest {

// use a unique dir so that it won't be conflict with other unit test which
// may also start a Mocked Frontend
private static String runningDir = "fe/mocked/AdminShowReplicaTest/" + UUID.randomUUID().toString() + "/";

private static ConnectContext connectContext;

@BeforeClass
public static void beforeClass() throws Exception {
UtFrameUtils.createDorisCluster(runningDir);

// create connect context
connectContext = UtFrameUtils.createDefaultCtx();

// create database
String createDbStmtStr = "create database test;";
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, connectContext);
Catalog.getCurrentCatalog().createDb(createDbStmt);

public class AdminShowReplicaTest extends TestWithFeService {
@Override
protected void runBeforeAll() throws Exception {
createDatabase("test");
createTable("create table test.tbl1\n" +
"(k1 date, k2 int)\n" +
"partition by range(k1)\n" +
"(\n" +
" partition p1 values less than(\"2021-07-01\"),\n" +
" partition p2 values less than(\"2021-08-01\")\n" +
")\n" +
"distributed by hash(k2) buckets 10\n" +
"properties(\"replication_num\" = \"1\");");
}

@AfterClass
public static void tearDown() {
File file = new File(runningDir);
file.delete();
}

private static void createTable(String sql) throws Exception {
CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
Catalog.getCurrentCatalog().createTable(createTableStmt);
"(k1 date, k2 int)\n" +
"partition by range(k1)\n" +
"(\n" +
" partition p1 values less than(\"2021-07-01\"),\n" +
" partition p2 values less than(\"2021-08-01\")\n" +
")\n" +
"distributed by hash(k2) buckets 10\n" +
"properties(\"replication_num\" = \"1\");");
}

@Test
public void testShowReplicaDistribution() throws Exception {
String stmtStr = "admin show replica distribution from test.tbl1 partition(p1)";
AdminShowReplicaDistributionStmt stmt = (AdminShowReplicaDistributionStmt) UtFrameUtils.parseAndAnalyzeStmt(
stmtStr, connectContext);
AdminShowReplicaDistributionStmt stmt = (AdminShowReplicaDistributionStmt) parseAndAnalyzeStmt(
stmtStr);
ShowExecutor executor = new ShowExecutor(connectContext, stmt);
ShowResultSet resultSet = executor.execute();
Assert.assertEquals(1, resultSet.getResultRows().size());
Assert.assertEquals(7, resultSet.getResultRows().get(0).size());

stmtStr = "show data skew from test.tbl1 partition(p1)";
ShowDataSkewStmt skewStmt = (ShowDataSkewStmt) UtFrameUtils.parseAndAnalyzeStmt(
stmtStr, connectContext);
ShowDataSkewStmt skewStmt = (ShowDataSkewStmt) parseAndAnalyzeStmt(stmtStr);
executor = new ShowExecutor(connectContext, skewStmt);
resultSet = executor.execute();
Assert.assertEquals(10, resultSet.getResultRows().size());
@@ -190,5 +157,4 @@ private boolean tryAssert(boolean correct, Exception e) {
return true;
}


}
@@ -21,34 +21,26 @@
import org.apache.doris.common.FeConstants;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.utframe.DorisAssert;
import org.apache.doris.utframe.TestWithFeService;
import org.apache.doris.utframe.UtFrameUtils;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.jupiter.api.Test;

import java.util.UUID;

public class AggregateTest {

private static String baseDir = "fe";
private static String runningDir = baseDir + "/mocked/AggregateTest/"
+ UUID.randomUUID().toString() + "/";
public class AggregateTest extends TestWithFeService {
private static final String TABLE_NAME = "table1";
private static final String DB_NAME = "db1";
private static DorisAssert dorisAssert;

@BeforeClass
public static void beforeClass() throws Exception{
@Override
protected void runBeforeAll() throws Exception {
FeConstants.runningUnitTest = true;
UtFrameUtils.createDorisCluster(runningDir);
dorisAssert = new DorisAssert();
dorisAssert.withDatabase(DB_NAME).useDatabase(DB_NAME);
String createTableSQL = "create table " + DB_NAME + "." + TABLE_NAME + " (empid int, name varchar, " +
"deptno int, salary int, commission int, time DATETIME) "
+ "distributed by hash(empid) buckets 3 properties('replication_num' = '1');";
dorisAssert.withTable(createTableSQL);
"deptno int, salary int, commission int, time DATETIME) "
+ "distributed by hash(empid) buckets 3 properties('replication_num' = '1');";
createTable(createTableSQL);
}

/**
@@ -181,9 +173,4 @@ public void testWindowFunnelAnalysisException() throws Exception {
Assert.fail("must be AnalysisException.");
} while(false);
}

@AfterClass
public static void afterClass() throws Exception {
UtFrameUtils.cleanDorisFeDir(baseDir);
}
}
@@ -17,29 +17,16 @@

package org.apache.doris.analysis;

import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.FeConstants;
import org.apache.doris.utframe.UtFrameUtils;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.UUID;
import org.junit.jupiter.api.Test;

public class ListPartitionPrunerTest extends PartitionPruneTestBase {

@BeforeClass
public static void beforeClass() throws Exception {
@Override
protected void runBeforeAll() throws Exception {
FeConstants.runningUnitTest = true;
runningDir = "fe/mocked/ListPartitionPrunerTest/" + UUID.randomUUID().toString() + "/";
UtFrameUtils.createDorisCluster(runningDir);

connectContext = UtFrameUtils.createDefaultCtx();

String createDbStmtStr = "create database test;";
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, connectContext);
Catalog.getCurrentCatalog().createDb(createDbStmt);
createDatabase("test");

String createSinglePartColWithSinglePartKey =
"create table test.t1\n"
@@ -84,15 +71,10 @@ public static void beforeClass() throws Exception {
+ "distributed by hash(k2) buckets 1\n"
+ "properties('replication_num' = '1');";

createTable(createSinglePartColWithSinglePartKey);
createTable(createSinglePartColWithMultiPartKey);
createTable(createMultiPartColWithSinglePartKey);
createTable(createMultiPartColWithMultiPartKey);
}

@AfterClass
public static void tearDown() throws Exception {
UtFrameUtils.cleanDorisFeDir(runningDir);
createTables(createSinglePartColWithSinglePartKey,
createSinglePartColWithMultiPartKey,
createMultiPartColWithSinglePartKey,
createMultiPartColWithMultiPartKey);
}

private void initTestCases() {
@@ -17,19 +17,14 @@

package org.apache.doris.analysis;

import org.apache.doris.catalog.Catalog;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.utframe.UtFrameUtils;
import org.apache.doris.utframe.TestWithFeService;

import org.junit.Assert;

import java.util.ArrayList;
import java.util.List;

public class PartitionPruneTestBase {
protected static String runningDir;
protected static ConnectContext connectContext;

public abstract class PartitionPruneTestBase extends TestWithFeService {
protected List<TestCase> cases = new ArrayList<>();

protected void doTest() throws Exception {
@@ -41,16 +36,10 @@ protected void doTest() throws Exception {
}
}

protected static void createTable(String sql) throws Exception {
CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(sql, connectContext);
Catalog.getCurrentCatalog().createTable(createTableStmt);
}

private void assertExplainContains(int version, String sql, String subString) throws Exception {
Assert.assertTrue(String.format("version=%d, sql=%s, expectResult=%s",
version, sql, subString),
UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql)
.contains(subString));
version, sql, subString),
getSQLPlanOrErrorMsg("explain " + sql).contains(subString));
}

protected void addCase(String sql, String v1Result, String v2Result) {

0 comments on commit 1746f61

Please sign in to comment.