Skip to content

Commit cdadb4a

Browse files
committed
add test case for admin interface error injection
1 parent 59931e1 commit cdadb4a

File tree

2 files changed

+175
-1
lines changed

2 files changed

+175
-1
lines changed

src/test/java/com/alipay/oceanbase/hbase/OHTableAdminInterfaceTest.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,58 @@ public OHTablePool setUpPool() throws IOException {
6767
return ohTablePool;
6868
}
6969

70+
enum ErrSimPoint {
71+
EN_CREATE_HTABLE_TG_FINISH_ERR(2621),
72+
EN_CREATE_HTABLE_CF_FINISH_ERR(2622),
73+
EN_DISABLE_HTABLE_CF_FINISH_ERR(2623),
74+
EN_DELETE_HTABLE_CF_FINISH_ERR(2624);
75+
76+
private final int errCode;
77+
78+
ErrSimPoint(int errCode) {
79+
this.errCode = errCode;
80+
}
81+
82+
public int getErrCode() {
83+
return errCode;
84+
}
85+
}
86+
87+
private void setErrSimPoint(ErrSimPoint errSimPoint, boolean enable) {
88+
java.sql.Connection connection = null;
89+
java.sql.Statement statement = null;
90+
91+
try {
92+
connection = ObHTableTestUtil.getSysTenantConnection();
93+
statement = connection.createStatement();
94+
95+
String sql = String.format(
96+
"alter system set_tp tp_no = %d, error_code = 4016, frequency = %d",
97+
errSimPoint.getErrCode(),
98+
enable ? 1 : 0
99+
);
100+
101+
statement.execute(sql);
102+
} catch (Exception e) {
103+
throw new RuntimeException("Error injection setup failed", e);
104+
} finally {
105+
if (statement != null) {
106+
try {
107+
statement.close();
108+
} catch (Exception e) {
109+
// ignore
110+
}
111+
}
112+
if (connection != null) {
113+
try {
114+
connection.close();
115+
} catch (Exception e) {
116+
// ignore
117+
}
118+
}
119+
}
120+
}
121+
70122
@Test
71123
public void testGetStartEndKeysOHTableClientRange() throws Exception {
72124
// Init OHTableClient
@@ -1209,4 +1261,72 @@ void checkKVAttributes(String tableName, String kvAttributes) throws Exception {
12091261
Assert.assertEquals(kvAttributes, value);
12101262
Assert.assertFalse(resultSet.next());
12111263
}
1264+
1265+
// NOTE: observer should build with `-DOB_ERRSIM=ON` option, otherwise the test will fail
1266+
// This test verifies error injection scenarios for table operations
1267+
@Test
1268+
public void testCreateTableInjectError() throws Exception {
1269+
Configuration conf = ObHTableTestUtil.newConfiguration();
1270+
Connection connection = ConnectionFactory.createConnection(conf);
1271+
Admin admin = connection.getAdmin();
1272+
1273+
byte[] tableName = Bytes.toBytes("test_create_table_inject_error");
1274+
byte[] cf1 = Bytes.toBytes("cf1");
1275+
byte[] cf2 = Bytes.toBytes("cf2");
1276+
byte[] cf3 = Bytes.toBytes("cf3");
1277+
1278+
HColumnDescriptor hcd1 = new HColumnDescriptor(cf1);
1279+
HColumnDescriptor hcd2 = new HColumnDescriptor(cf2);
1280+
HColumnDescriptor hcd3 = new HColumnDescriptor(cf3);
1281+
1282+
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
1283+
htd.addFamily(hcd1);
1284+
htd.addFamily(hcd2);
1285+
htd.addFamily(hcd3);
1286+
1287+
// 1. open err EN_CREATE_HTABLE_TG_FINISH_ERR
1288+
setErrSimPoint(ErrSimPoint.EN_CREATE_HTABLE_TG_FINISH_ERR, true);
1289+
ObHTableTestUtil.executeIgnoreUnexpectedError(() -> admin.createTable(htd));
1290+
assertFalse("Table should not exist after TG error injection",
1291+
admin.tableExists(TableName.valueOf(tableName)));
1292+
setErrSimPoint(ErrSimPoint.EN_CREATE_HTABLE_TG_FINISH_ERR, false);
1293+
1294+
// 2. open err EN_CREATE_HTABLE_CF_FINISH_ERR
1295+
setErrSimPoint(ErrSimPoint.EN_CREATE_HTABLE_CF_FINISH_ERR, true);
1296+
ObHTableTestUtil.executeIgnoreUnexpectedError(() -> admin.createTable(htd));
1297+
assertFalse("Table should not exist after CF error injection",
1298+
admin.tableExists(TableName.valueOf(tableName)));
1299+
setErrSimPoint(ErrSimPoint.EN_CREATE_HTABLE_CF_FINISH_ERR, false);
1300+
1301+
// 3. create table without error
1302+
admin.createTable(htd);
1303+
assertTrue("Table should exist after normal creation",
1304+
admin.tableExists(TableName.valueOf(tableName)));
1305+
assertEquals("Table should have 3 column families", 3,
1306+
admin.getTableDescriptor(TableName.valueOf(tableName)).getFamilies().size());
1307+
1308+
// 4. open err EN_DISABLE_HTABLE_CF_FINISH_ERR
1309+
setErrSimPoint(ErrSimPoint.EN_DISABLE_HTABLE_CF_FINISH_ERR, true);
1310+
admin.disableTable(TableName.valueOf(tableName));
1311+
assertFalse("Table should not be disabled after disable error injection",
1312+
admin.isTableDisabled(TableName.valueOf(tableName)));
1313+
setErrSimPoint(ErrSimPoint.EN_DISABLE_HTABLE_CF_FINISH_ERR, false);
1314+
1315+
// 5. disable table without error
1316+
admin.disableTable(TableName.valueOf(tableName));
1317+
assertTrue("Table should be disabled after normal disable",
1318+
admin.isTableDisabled(TableName.valueOf(tableName)));
1319+
1320+
// 6. open err EN_DELETE_HTABLE_CF_FINISH_ERR
1321+
setErrSimPoint(ErrSimPoint.EN_DELETE_HTABLE_CF_FINISH_ERR, true);
1322+
admin.deleteTable(TableName.valueOf(tableName));
1323+
assertTrue("Table should still exist after delete error injection",
1324+
admin.tableExists(TableName.valueOf(tableName)));
1325+
setErrSimPoint(ErrSimPoint.EN_DELETE_HTABLE_CF_FINISH_ERR, false);
1326+
1327+
// 7. delete table without error
1328+
admin.deleteTable(TableName.valueOf(tableName));
1329+
assertFalse("Table should not exist after normal delete",
1330+
admin.tableExists(TableName.valueOf(tableName)));
1331+
}
12121332
}

src/test/java/com/alipay/oceanbase/hbase/util/ObHTableTestUtil.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ public class ObHTableTestUtil {
5555
+ "oceanbase?" + "useUnicode=TRUE&"
5656
+ "characterEncoding=utf-8&"
5757
+ "socketTimeout=3000000&" + "connectTimeout=60000";
58+
public static String SYS_TENANT_JDBC_URL = "jdbc:mysql://" + JDBC_IP + ":" + JDBC_PORT + "/ "
59+
+ "oceanbase?" + "useUnicode=TRUE&"
60+
+ "characterEncoding=utf-8&"
61+
+ "socketTimeout=3000000&" + "connectTimeout=60000";
5862

63+
public static String SYS_TENANT_USER_NAME = "root@sys";
64+
public static String SYS_TENANT_PASSWORD = "";
5965
public static String SQL_FORMAT = "truncate %s";
6066
public static List<String> tableNameList = new LinkedList<String>();
6167
public static Connection conn;
@@ -172,6 +178,17 @@ static public Connection getSysConnection() {
172178
}
173179
}
174180

181+
static public Connection getSysTenantConnection() {
182+
try {
183+
Class.forName("com.mysql.cj.jdbc.Driver");
184+
Connection conn = DriverManager
185+
.getConnection(SYS_TENANT_JDBC_URL, SYS_TENANT_USER_NAME, SYS_TENANT_PASSWORD);
186+
return conn;
187+
} catch (Exception e) {
188+
throw new RuntimeException(e);
189+
}
190+
}
191+
175192
@FunctionalInterface
176193
public interface CheckedConsumer<T> {
177194
void accept(T t) throws Throwable;
@@ -234,4 +251,41 @@ public static void executeSQL(Connection conn, String sql, boolean printSQL) thr
234251
System.out.println("execute sql: " + sql);
235252
conn.createStatement().execute(sql);
236253
}
237-
}
254+
255+
@FunctionalInterface
256+
public interface CheckedRunnable {
257+
void run() throws Exception;
258+
}
259+
260+
public static void executeIgnoreUnexpectedError(CheckedRunnable operation) throws Exception {
261+
executeIgnoreExpectedErrors(operation, "OB_ERR_UNEXPECTED");
262+
}
263+
264+
public static void executeIgnoreExpectedErrors(CheckedRunnable operation, String... expectedErrorMessages) throws Exception {
265+
try {
266+
operation.run();
267+
} catch (Exception e) {
268+
boolean shouldIgnore = false;
269+
String[] messagesToCheck = {
270+
e.getMessage(),
271+
e.getCause() != null ? e.getCause().getMessage() : null
272+
};
273+
274+
for (String expectedMessage : expectedErrorMessages) {
275+
for (String actualMessage : messagesToCheck) {
276+
if (actualMessage != null && actualMessage.contains(expectedMessage)) {
277+
shouldIgnore = true;
278+
break;
279+
}
280+
}
281+
if (shouldIgnore) {
282+
break;
283+
}
284+
}
285+
286+
if (!shouldIgnore) {
287+
throw e;
288+
}
289+
}
290+
}
291+
}

0 commit comments

Comments
 (0)