log4j
diff --git a/tests/examples/JDBC/JDBCDemo/readme.md b/tests/examples/JDBC/JDBCDemo/readme.md
index 9b8790adaddb20246232392dd323ec502102fa18..e348e458fe938c4f2381c448f3c15e60af27040e 100644
--- a/tests/examples/JDBC/JDBCDemo/readme.md
+++ b/tests/examples/JDBC/JDBCDemo/readme.md
@@ -6,10 +6,24 @@ TDengine's JDBC demo project is organized in a Maven way so that users can easil
Make sure you have already installed a tdengine client on your current develop environment.
Download the tdengine package on our website: ``https://www.taosdata.com/cn/all-downloads/`` and install the client.
+## How to run jdbcChecker
+mvn clean compile exec:java -Dexec.mainClass="com.taosdata.example.JdbcChecker" -Dexec.args="-host localhost"
+
+## How to run jdbcTaosDemo
+run command:
+ mvn clean compile exec:java -Dexec.mainClass="com.taosdata.example.jdbcTaosdemo.JdbcTaosdemo"
+and run with your customed args
+mvn clean compile exec:java -Dexec.mainClass="com.taosdata.example.jdbcTaosdemo.JdbcTaosdemo" -Dexec.args="-host localhost"
+
## Compile the Demo Code and Run It
+
To compile the demo project, go to the source directory ``TDengine/tests/examples/JDBC/JDBCDemo`` and execute
-mvn clean package assembly:single
+
+
+mvn clean package assembly:single
+
+
The ``pom.xml`` is configured to package all the dependencies into one executable jar file.
To run it, go to ``examples/JDBC/JDBCDemo/target`` and execute
-java -jar jdbcChecker-SNAPSHOT-jar-with-dependencies.jar -host localhost
\ No newline at end of file
+java -jar jdbcChecker-SNAPSHOT-jar-with-dependencies.jar -host localhost
diff --git a/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/domain/JdbcTaosdemoConfig.java b/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/domain/JdbcTaosdemoConfig.java
index 82613037dbccd3be1f2c8a85a2f25e7a25ffad01..36745a93941cc690f37d06d9a3662605723bbd2c 100644
--- a/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/domain/JdbcTaosdemoConfig.java
+++ b/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/domain/JdbcTaosdemoConfig.java
@@ -14,9 +14,9 @@ public final class JdbcTaosdemoConfig {
//Destination database. Default is 'test'
private String dbName = "test";
//keep
- private int keep = 3650;
+ private int keep = 36500;
//days
- private int days = 10;
+ private int days = 120;
//Super table Name. Default is 'meters'
private String stbName = "meters";
diff --git a/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/task/InsertTableTask.java b/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/task/InsertTableTask.java
index a35628bb58c6630d92bd2b6aebb09f9912e57536..644de52dd3e75a77c2d635a6f5328f186259096c 100644
--- a/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/task/InsertTableTask.java
+++ b/tests/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/jdbcTaosdemo/task/InsertTableTask.java
@@ -41,7 +41,7 @@ public class InsertTableTask implements Runnable {
long ts = start.toEpochMilli() + (j * timeGap);
// insert data into echo table
for (int i = startTbIndex; i < startTbIndex + tableNumber; i++) {
- String sql = SqlSpeller.insertOneRowSQL(config.getDbName(), config.getTbPrefix(), i + 1, ts);
+ String sql = SqlSpeller.insertBatchSizeRowsSQL(config.getDbName(), config.getTbPrefix(), i + 1, ts, config.getNumberOfRecordsPerRequest());
logger.info(Thread.currentThread().getName() + ">>> " + sql);
Statement statement = connection.createStatement();
statement.execute(sql);
diff --git a/tests/pytest/client/alterDatabase.py b/tests/pytest/client/alterDatabase.py
index fa397d16c57625d53f6f1b2772afa99ade314e1a..8191312cc060f9c20632911c956065f777d47079 100644
--- a/tests/pytest/client/alterDatabase.py
+++ b/tests/pytest/client/alterDatabase.py
@@ -32,9 +32,9 @@ class TDTestCase:
tdSql.query("show databases")
tdSql.checkData(0, 14, 2)
- tdSql.execute("alter database db keep 365")
+ tdSql.execute("alter database db keep 365,365,365")
tdSql.query("show databases")
- tdSql.checkData(0, 7, "3650,3650,365")
+ tdSql.checkData(0, 7, "365,365,365")
tdSql.execute("alter database db quorum 2")
tdSql.query("show databases")
diff --git a/tests/pytest/crash_gen/crash_gen_main.py b/tests/pytest/crash_gen/crash_gen_main.py
index 8d68457ec8d07c9c00f8b8fd0a11e2f25284ce4a..e2ce4b26fa2fa8cc9c601218c1bf19d838b57c46 100755
--- a/tests/pytest/crash_gen/crash_gen_main.py
+++ b/tests/pytest/crash_gen/crash_gen_main.py
@@ -352,6 +352,12 @@ class ThreadCoordinator:
self._execStats.registerFailure("Broken DB Connection")
# continue # don't do that, need to tap all threads at
# end, and maybe signal them to stop
+ if isinstance(err, CrashGenError): # our own transition failure
+ Logging.info("State transition error")
+ traceback.print_stack()
+ transitionFailed = True
+ self._te = None # Not running any more
+ self._execStats.registerFailure("State transition error")
else:
raise
# return transitionFailed # Why did we have this??!!
@@ -388,12 +394,20 @@ class ThreadCoordinator:
self._syncAtBarrier() # For now just cross the barrier
Progress.emit(Progress.END_THREAD_STEP)
except threading.BrokenBarrierError as err:
- Logging.info("Main loop aborted, caused by worker thread(s) time-out")
self._execStats.registerFailure("Aborted due to worker thread timeout")
- print("\n\nWorker Thread time-out detected, TAOS related threads are:")
+ Logging.error("\n")
+ Logging.error("Main loop aborted, caused by worker thread(s) time-out of {} seconds".format(
+ ThreadCoordinator.WORKER_THREAD_TIMEOUT))
+ Logging.error("TAOS related threads blocked at (stack frames top-to-bottom):")
ts = ThreadStacks()
ts.print(filterInternal=True)
workerTimeout = True
+
+ # Enable below for deadlock debugging, using gdb to attach to process
+ # while True:
+ # Logging.error("Deadlock detected")
+ # time.sleep(60.0)
+
break
# At this point, all threads should be pass the overall "barrier" and before the per-thread "gate"
@@ -701,7 +715,7 @@ class AnyState:
# task.logDebug("Task success found")
sCnt += 1
if (sCnt >= 2):
- raise RuntimeError(
+ raise CrashGenError(
"Unexpected more than 1 success with task: {}".format(cls))
def assertIfExistThenSuccess(self, tasks, cls):
@@ -714,7 +728,7 @@ class AnyState:
if task.isSuccess():
sCnt += 1
if (exists and sCnt <= 0):
- raise RuntimeError("Unexpected zero success for task type: {}, from tasks: {}"
+ raise CrashGenError("Unexpected zero success for task type: {}, from tasks: {}"
.format(cls, tasks))
def assertNoTask(self, tasks, cls):
@@ -727,7 +741,7 @@ class AnyState:
for task in tasks:
if isinstance(task, cls):
if task.isSuccess():
- raise RuntimeError(
+ raise CrashGenError(
"Unexpected successful task: {}".format(cls))
def hasSuccess(self, tasks, cls):
@@ -926,8 +940,9 @@ class StateMechine:
Logging.debug("[STT] DB_ONLY found, between {} and {}".format(ts, time.time()))
return StateDbOnly()
+ # For sure we have tables, which means we must have the super table. # TODO: are we sure?
sTable = self._db.getFixedSuperTable()
- if sTable.hasRegTables(dbc, dbName): # no regular tables
+ if sTable.hasRegTables(dbc): # no regular tables
Logging.debug("[STT] SUPER_TABLE_ONLY found, between {} and {}".format(ts, time.time()))
return StateSuperTableOnly()
else: # has actual tables
@@ -1050,9 +1065,8 @@ class Database:
def getFixedSuperTableName(cls):
return "fs_table"
- @classmethod
- def getFixedSuperTable(cls) -> TdSuperTable:
- return TdSuperTable(cls.getFixedSuperTableName())
+ def getFixedSuperTable(self) -> TdSuperTable:
+ return TdSuperTable(self.getFixedSuperTableName(), self.getName())
# We aim to create a starting time tick, such that, whenever we run our test here once
# We should be able to safely create 100,000 records, which will not have any repeated time stamp
@@ -1107,6 +1121,11 @@ class Database:
# print("Float obtained: {}".format(ret))
return ret
+ ALL_COLORS = ['red', 'white', 'blue', 'green', 'purple']
+
+ def getNextColor(self):
+ return random.choice(self.ALL_COLORS)
+
class TaskExecutor():
class BoundedList:
@@ -1240,7 +1259,7 @@ class Task():
if errno in [
0x05, # TSDB_CODE_RPC_NOT_READY
0x0B, # Unable to establish connection, more details in TD-1648
- 0x200, # invalid SQL, TODO: re-examine with TD-934
+ # 0x200, # invalid SQL, TODO: re-examine with TD-934
0x20F, # query terminated, possibly due to vnoding being dropped, see TD-1776
0x213, # "Disconnected from service", result of "kill connection ???"
0x217, # "db not selected", client side defined error code
@@ -1569,8 +1588,8 @@ class TaskCreateSuperTable(StateTransitionTask):
sTable = self._db.getFixedSuperTable() # type: TdSuperTable
# wt.execSql("use db") # should always be in place
- sTable.create(wt.getDbConn(), self._db.getName(),
- {'ts':'timestamp', 'speed':'int'}, {'b':'binary(200)', 'f':'float'},
+ sTable.create(wt.getDbConn(),
+ {'ts':'TIMESTAMP', 'speed':'INT', 'color':'BINARY(16)'}, {'b':'BINARY(200)', 'f':'FLOAT'},
dropIfExists = True
)
# self.execWtSql(wt,"create table db.{} (ts timestamp, speed int) tags (b binary(200), f float) ".format(tblName))
@@ -1579,30 +1598,33 @@ class TaskCreateSuperTable(StateTransitionTask):
class TdSuperTable:
- def __init__(self, stName):
+ def __init__(self, stName, dbName):
self._stName = stName
+ self._dbName = dbName
def getName(self):
return self._stName
- def drop(self, dbc, dbName, skipCheck = False):
- if self.exists(dbc, dbName) : # if myself exists
+ def drop(self, dbc, skipCheck = False):
+ dbName = self._dbName
+ if self.exists(dbc) : # if myself exists
fullTableName = dbName + '.' + self._stName
dbc.execute("DROP TABLE {}".format(fullTableName))
else:
if not skipCheck:
raise CrashGenError("Cannot drop non-existant super table: {}".format(self._stName))
- def exists(self, dbc, dbName):
- dbc.execute("USE " + dbName)
+ def exists(self, dbc):
+ dbc.execute("USE " + self._dbName)
return dbc.existsSuperTable(self._stName)
# TODO: odd semantic, create() method is usually static?
- def create(self, dbc, dbName, cols: dict, tags: dict,
+ def create(self, dbc, cols: dict, tags: dict,
dropIfExists = False
):
-
'''Creating a super table'''
+
+ dbName = self._dbName
dbc.execute("USE " + dbName)
fullTableName = dbName + '.' + self._stName
if dbc.existsSuperTable(self._stName):
@@ -1623,7 +1645,8 @@ class TdSuperTable:
)
dbc.execute(sql)
- def getRegTables(self, dbc: DbConn, dbName: str):
+ def getRegTables(self, dbc: DbConn):
+ dbName = self._dbName
try:
dbc.query("select TBNAME from {}.{}".format(dbName, self._stName)) # TODO: analyze result set later
except taos.error.ProgrammingError as err:
@@ -1634,10 +1657,11 @@ class TdSuperTable:
qr = dbc.getQueryResult()
return [v[0] for v in qr] # list transformation, ref: https://stackoverflow.com/questions/643823/python-list-transformation
- def hasRegTables(self, dbc: DbConn, dbName: str):
- return dbc.query("SELECT * FROM {}.{}".format(dbName, self._stName)) > 0
+ def hasRegTables(self, dbc: DbConn):
+ return dbc.query("SELECT * FROM {}.{}".format(self._dbName, self._stName)) > 0
- def ensureTable(self, task: Task, dbc: DbConn, dbName: str, regTableName: str):
+ def ensureTable(self, task: Task, dbc: DbConn, regTableName: str):
+ dbName = self._dbName
sql = "select tbname from {}.{} where tbname in ('{}')".format(dbName, self._stName, regTableName)
if dbc.query(sql) >= 1 : # reg table exists already
return
@@ -1650,15 +1674,15 @@ class TdSuperTable:
# print("(" + fullTableName[-3:] + ")", end="", flush=True)
try:
sql = "CREATE TABLE {} USING {}.{} tags ({})".format(
- fullTableName, dbName, self._stName, self._getTagStrForSql(dbc, dbName)
+ fullTableName, dbName, self._stName, self._getTagStrForSql(dbc)
)
dbc.execute(sql)
finally:
if task is not None:
task.unlockTable(fullTableName) # no matter what
- def _getTagStrForSql(self, dbc, dbName: str) :
- tags = self._getTags(dbc, dbName)
+ def _getTagStrForSql(self, dbc) :
+ tags = self._getTags(dbc)
tagStrs = []
for tagName in tags:
tagType = tags[tagName]
@@ -1672,36 +1696,86 @@ class TdSuperTable:
raise RuntimeError("Unexpected tag type: {}".format(tagType))
return ", ".join(tagStrs)
- def _getTags(self, dbc, dbName) -> dict:
- dbc.query("DESCRIBE {}.{}".format(dbName, self._stName))
+ def _getTags(self, dbc) -> dict:
+ dbc.query("DESCRIBE {}.{}".format(self._dbName, self._stName))
stCols = dbc.getQueryResult()
# print(stCols)
ret = {row[0]:row[1] for row in stCols if row[3]=='TAG'} # name:type
# print("Tags retrieved: {}".format(ret))
return ret
- def addTag(self, dbc, dbName, tagName, tagType):
- if tagName in self._getTags(dbc, dbName): # already
+ def addTag(self, dbc, tagName, tagType):
+ if tagName in self._getTags(dbc): # already
return
# sTable.addTag("extraTag", "int")
- sql = "alter table {}.{} add tag {} {}".format(dbName, self._stName, tagName, tagType)
+ sql = "alter table {}.{} add tag {} {}".format(
+ self._dbName, self._stName, tagName, tagType)
dbc.execute(sql)
- def dropTag(self, dbc, dbName, tagName):
- if not tagName in self._getTags(dbc, dbName): # don't have this tag
+ def dropTag(self, dbc, tagName):
+ if not tagName in self._getTags(dbc): # don't have this tag
return
- sql = "alter table {}.{} drop tag {}".format(dbName, self._stName, tagName)
+ sql = "alter table {}.{} drop tag {}".format(self._dbName, self._stName, tagName)
dbc.execute(sql)
- def changeTag(self, dbc, dbName, oldTag, newTag):
- tags = self._getTags(dbc, dbName)
+ def changeTag(self, dbc, oldTag, newTag):
+ tags = self._getTags(dbc)
if not oldTag in tags: # don't have this tag
return
if newTag in tags: # already have this tag
return
- sql = "alter table {}.{} change tag {} {}".format(dbName, self._stName, oldTag, newTag)
+ sql = "alter table {}.{} change tag {} {}".format(self._dbName, self._stName, oldTag, newTag)
dbc.execute(sql)
+ def generateQueries(self, dbc: DbConn) -> List[SqlQuery]:
+ ''' Generate queries to test/exercise this super table '''
+ ret = [] # type: List[SqlQuery]
+
+ for rTbName in self.getRegTables(dbc): # regular tables
+
+ filterExpr = Dice.choice([ # TODO: add various kind of WHERE conditions
+ None
+ ])
+
+ # Run the query against the regular table first
+ doAggr = (Dice.throw(2) == 0) # 1 in 2 chance
+ if not doAggr: # don't do aggregate query, just simple one
+ ret.append(SqlQuery( # reg table
+ "select {} from {}.{}".format('*', self._dbName, rTbName)))
+ ret.append(SqlQuery( # super table
+ "select {} from {}.{}".format('*', self._dbName, self.getName())))
+ else: # Aggregate query
+ aggExpr = Dice.choice([
+ 'count(*)',
+ 'avg(speed)',
+ # 'twa(speed)', # TODO: this one REQUIRES a where statement, not reasonable
+ 'sum(speed)',
+ 'stddev(speed)',
+ # SELECTOR functions
+ 'min(speed)',
+ 'max(speed)',
+ 'first(speed)',
+ 'last(speed)',
+ 'top(speed, 50)', # TODO: not supported?
+ 'bottom(speed, 50)', # TODO: not supported?
+ 'apercentile(speed, 10)', # TODO: TD-1316
+ 'last_row(speed)',
+ # Transformation Functions
+ # 'diff(speed)', # TODO: no supported?!
+ 'spread(speed)'
+ ]) # TODO: add more from 'top'
+
+
+ if aggExpr not in ['stddev(speed)']: #TODO: STDDEV not valid for super tables?!
+ sql = "select {} from {}.{}".format(aggExpr, self._dbName, self.getName())
+ if Dice.throw(3) == 0: # 1 in X chance
+ sql = sql + ' GROUP BY color'
+ Progress.emit(Progress.QUERY_GROUP_BY)
+ # Logging.info("Executing GROUP-BY query: " + sql)
+ ret.append(SqlQuery(sql))
+
+ return ret
+
class TaskReadData(StateTransitionTask):
@classmethod
def getEndState(cls):
@@ -1716,10 +1790,8 @@ class TaskReadData(StateTransitionTask):
# return True # always
# return gSvcMgr.isActive() # only if it's running TODO: race condition here
- def _executeInternal(self, te: TaskExecutor, wt: WorkerThread):
- sTable = self._db.getFixedSuperTable()
-
- # 1 in 5 chance, simulate a broken connection, only if service stable (not restarting)
+ def _reconnectIfNeeded(self, wt):
+ # 1 in 20 chance, simulate a broken connection, only if service stable (not restarting)
if random.randrange(20)==0: # and self._canRestartService(): # TODO: break connection in all situations
# Logging.info("Attempting to reconnect to server") # TODO: change to DEBUG
Progress.emit(Progress.SERVICE_RECONNECT_START)
@@ -1744,43 +1816,36 @@ class TaskReadData(StateTransitionTask):
return # TODO: fix server restart status race condtion
+ def _executeInternal(self, te: TaskExecutor, wt: WorkerThread):
+ self._reconnectIfNeeded(wt)
+
dbc = wt.getDbConn()
- dbName = self._db.getName()
- for rTbName in sTable.getRegTables(dbc, dbName): # regular tables
- aggExpr = Dice.choice([
- '*',
- 'count(*)',
- 'avg(speed)',
- # 'twa(speed)', # TODO: this one REQUIRES a where statement, not reasonable
- 'sum(speed)',
- 'stddev(speed)',
- # SELECTOR functions
- 'min(speed)',
- 'max(speed)',
- 'first(speed)',
- 'last(speed)',
- 'top(speed, 50)', # TODO: not supported?
- 'bottom(speed, 50)', # TODO: not supported?
- 'apercentile(speed, 10)', # TODO: TD-1316
- 'last_row(speed)',
- # Transformation Functions
- # 'diff(speed)', # TODO: no supported?!
- 'spread(speed)'
- ]) # TODO: add more from 'top'
- filterExpr = Dice.choice([ # TODO: add various kind of WHERE conditions
- None
- ])
+ sTable = self._db.getFixedSuperTable()
+
+ for q in sTable.generateQueries(dbc): # regular tables
try:
- # Run the query against the regular table first
- dbc.execute("select {} from {}.{}".format(aggExpr, dbName, rTbName))
- # Then run it against the super table
- if aggExpr not in ['stddev(speed)']: #TODO: STDDEV not valid for super tables?!
- dbc.execute("select {} from {}.{}".format(aggExpr, dbName, sTable.getName()))
+ sql = q.getSql()
+ # if 'GROUP BY' in sql:
+ # Logging.info("Executing GROUP-BY query: " + sql)
+ dbc.execute(sql)
except taos.error.ProgrammingError as err:
errno2 = Helper.convertErrno(err.errno)
Logging.debug("[=] Read Failure: errno=0x{:X}, msg: {}, SQL: {}".format(errno2, err, dbc.getLastSql()))
raise
+class SqlQuery:
+ @classmethod
+ def buildRandom(cls, db: Database):
+ '''Build a random query against a certain database'''
+
+ dbName = db.getName()
+
+ def __init__(self, sql:str = None):
+ self._sql = sql
+
+ def getSql(self):
+ return self._sql
+
class TaskDropSuperTable(StateTransitionTask):
@classmethod
def getEndState(cls):
@@ -1837,19 +1902,18 @@ class TaskAlterTags(StateTransitionTask):
# tblName = self._dbManager.getFixedSuperTableName()
dbc = wt.getDbConn()
sTable = self._db.getFixedSuperTable()
- dbName = self._db.getName()
dice = Dice.throw(4)
if dice == 0:
- sTable.addTag(dbc, dbName, "extraTag", "int")
+ sTable.addTag(dbc, "extraTag", "int")
# sql = "alter table db.{} add tag extraTag int".format(tblName)
elif dice == 1:
- sTable.dropTag(dbc, dbName, "extraTag")
+ sTable.dropTag(dbc, "extraTag")
# sql = "alter table db.{} drop tag extraTag".format(tblName)
elif dice == 2:
- sTable.dropTag(dbc, dbName, "newTag")
+ sTable.dropTag(dbc, "newTag")
# sql = "alter table db.{} drop tag newTag".format(tblName)
else: # dice == 3
- sTable.changeTag(dbc, dbName, "extraTag", "newTag")
+ sTable.changeTag(dbc, "extraTag", "newTag")
# sql = "alter table db.{} change tag extraTag newTag".format(tblName)
class TaskRestartService(StateTransitionTask):
@@ -1920,15 +1984,17 @@ class TaskAddData(StateTransitionTask):
for j in range(numRecords): # number of records per table
nextInt = db.getNextInt()
nextTick = db.getNextTick()
- sql += "('{}', {});".format(nextTick, nextInt)
+ nextColor = db.getNextColor()
+ sql += "('{}', {}, '{}');".format(nextTick, nextInt, nextColor)
dbc.execute(sql)
- def _addData(self, db, dbc, regTableName, te: TaskExecutor): # implied: NOT in batches
+ def _addData(self, db: Database, dbc, regTableName, te: TaskExecutor): # implied: NOT in batches
numRecords = self.LARGE_NUMBER_OF_RECORDS if gConfig.larger_data else self.SMALL_NUMBER_OF_RECORDS
for j in range(numRecords): # number of records per table
nextInt = db.getNextInt()
nextTick = db.getNextTick()
+ nextColor = db.getNextColor()
if gConfig.record_ops:
self.prepToRecordOps()
self.fAddLogReady.write("Ready to write {} to {}\n".format(nextInt, regTableName))
@@ -1942,11 +2008,11 @@ class TaskAddData(StateTransitionTask):
# print("_w" + str(nextInt % 100), end="", flush=True) # Trace what was written
try:
- sql = "insert into {} values ('{}', {});".format( # removed: tags ('{}', {})
+ sql = "insert into {} values ('{}', {}, '{}');".format( # removed: tags ('{}', {})
fullTableName,
# ds.getFixedSuperTableName(),
# ds.getNextBinary(), ds.getNextFloat(),
- nextTick, nextInt)
+ nextTick, nextInt, nextColor)
dbc.execute(sql)
except: # Any exception at all
if gConfig.verify_data:
@@ -1964,10 +2030,10 @@ class TaskAddData(StateTransitionTask):
.format(nextInt, readBack), 0x999)
except taos.error.ProgrammingError as err:
errno = Helper.convertErrno(err.errno)
- if errno in [0x991, 0x992] : # not a single result
+ if errno in [CrashGenError.INVALID_EMPTY_RESULT, CrashGenError.INVALID_MULTIPLE_RESULT] : # not a single result
raise taos.error.ProgrammingError(
"Failed to read back same data for tick: {}, wrote: {}, read: {}"
- .format(nextTick, nextInt, "Empty Result" if errno==0x991 else "Multiple Result"),
+ .format(nextTick, nextInt, "Empty Result" if errno == CrashGenError.INVALID_EMPTY_RESULT else "Multiple Result"),
errno)
elif errno in [0x218, 0x362]: # table doesn't exist
# do nothing
@@ -2000,11 +2066,12 @@ class TaskAddData(StateTransitionTask):
else:
self.activeTable.add(i) # marking it active
+ dbName = db.getName()
sTable = db.getFixedSuperTable()
regTableName = self.getRegTableName(i) # "db.reg_table_{}".format(i)
- fullTableName = db.getName() + '.' + regTableName
+ fullTableName = dbName + '.' + regTableName
# self._lockTable(fullTableName) # "create table" below. Stop it if the table is "locked"
- sTable.ensureTable(self, wt.getDbConn(), db.getName(), regTableName) # Ensure the table exists
+ sTable.ensureTable(self, wt.getDbConn(), regTableName) # Ensure the table exists
# self._unlockTable(fullTableName)
if Dice.throw(1) == 0: # 1 in 2 chance
@@ -2024,7 +2091,7 @@ class ThreadStacks: # stack info for all threads
self._allStacks[th.native_id] = stack
def print(self, filteredEndName = None, filterInternal = False):
- for thNid, stack in self._allStacks.items(): # for each thread
+ for thNid, stack in self._allStacks.items(): # for each thread, stack frames top to bottom
lastFrame = stack[-1]
if filteredEndName: # we need to filter out stacks that match this name
if lastFrame.name == filteredEndName : # end did not match
@@ -2036,9 +2103,9 @@ class ThreadStacks: # stack info for all threads
'__init__']: # the thread that extracted the stack
continue # ignore
# Now print
- print("\n<----- Thread Info for LWP/ID: {} (Execution stopped at Bottom Frame) <-----".format(thNid))
+ print("\n<----- Thread Info for LWP/ID: {} (most recent call last) <-----".format(thNid))
stackFrame = 0
- for frame in stack:
+ for frame in stack: # was using: reversed(stack)
# print(frame)
print("[{sf}] File {filename}, line {lineno}, in {name}".format(
sf=stackFrame, filename=frame.filename, lineno=frame.lineno, name=frame.name))
diff --git a/tests/pytest/crash_gen/db.py b/tests/pytest/crash_gen/db.py
index 2a4b362f82c4516195becf78ef9771b7c62c3c41..855e18be55fd5ae0d88865644a2ebfc836b7ccf3 100644
--- a/tests/pytest/crash_gen/db.py
+++ b/tests/pytest/crash_gen/db.py
@@ -78,7 +78,7 @@ class DbConn:
if nRows != 1:
raise taos.error.ProgrammingError(
"Unexpected result for query: {}, rows = {}".format(sql, nRows),
- (0x991 if nRows==0 else 0x992)
+ (CrashGenError.INVALID_EMPTY_RESULT if nRows==0 else CrashGenError.INVALID_MULTIPLE_RESULT)
)
if self.getResultRows() != 1 or self.getResultCols() != 1:
raise RuntimeError("Unexpected result set for query: {}".format(sql))
@@ -349,7 +349,8 @@ class DbConnNative(DbConn):
def execute(self, sql):
if (not self.isOpen):
- raise RuntimeError("Cannot execute database commands until connection is open")
+ raise CrashGenError(
+ "Cannot exec SQL unless db connection is open", CrashGenError.DB_CONNECTION_NOT_OPEN)
Logging.debug("[SQL] Executing SQL: {}".format(sql))
self._lastSql = sql
nRows = self._tdSql.execute(sql)
@@ -360,8 +361,8 @@ class DbConnNative(DbConn):
def query(self, sql): # return rows affected
if (not self.isOpen):
- raise RuntimeError(
- "Cannot query database until connection is open")
+ raise CrashGenError(
+ "Cannot query database until connection is open, restarting?", CrashGenError.DB_CONNECTION_NOT_OPEN)
Logging.debug("[SQL] Executing SQL: {}".format(sql))
self._lastSql = sql
nRows = self._tdSql.query(sql)
diff --git a/tests/pytest/crash_gen/misc.py b/tests/pytest/crash_gen/misc.py
index 2d2ce99d95582809a8940a8d777bc166b633747c..a374ed943b41b52c2ccbee0825bca3080ed43ea9 100644
--- a/tests/pytest/crash_gen/misc.py
+++ b/tests/pytest/crash_gen/misc.py
@@ -3,14 +3,20 @@ import random
import logging
import os
+import taos
-class CrashGenError(Exception):
- def __init__(self, msg=None, errno=None):
- self.msg = msg
- self.errno = errno
- def __str__(self):
- return self.msg
+class CrashGenError(taos.error.ProgrammingError):
+ INVALID_EMPTY_RESULT = 0x991
+ INVALID_MULTIPLE_RESULT = 0x992
+ DB_CONNECTION_NOT_OPEN = 0x993
+ # def __init__(self, msg=None, errno=None):
+ # self.msg = msg
+ # self.errno = errno
+
+ # def __str__(self):
+ # return self.msg
+ pass
class LoggingFilter(logging.Filter):
@@ -168,6 +174,7 @@ class Progress:
SERVICE_RECONNECT_FAILURE = 6
SERVICE_START_NAP = 7
CREATE_TABLE_ATTEMPT = 8
+ QUERY_GROUP_BY = 9
tokens = {
STEP_BOUNDARY: '.',
@@ -178,7 +185,8 @@ class Progress:
SERVICE_RECONNECT_SUCCESS: '.r>',
SERVICE_RECONNECT_FAILURE: '.xr>',
SERVICE_START_NAP: '_zz',
- CREATE_TABLE_ATTEMPT: '_c',
+ CREATE_TABLE_ATTEMPT: 'c',
+ QUERY_GROUP_BY: 'g',
}
@classmethod
diff --git a/tests/pytest/crash_gen/service_manager.py b/tests/pytest/crash_gen/service_manager.py
index d249abc4396462b6dbacbfcbb1f6619e48161c3b..ae6f8d5d3a5a4d6a8bf745a48ec2368aa5e832ad 100644
--- a/tests/pytest/crash_gen/service_manager.py
+++ b/tests/pytest/crash_gen/service_manager.py
@@ -51,10 +51,12 @@ class TdeInstance():
def prepareGcovEnv(cls, env):
# Ref: https://gcc.gnu.org/onlinedocs/gcc/Cross-profiling.html
bPath = cls._getBuildPath() # build PATH
- numSegments = len(bPath.split('/')) - 1 # "/x/TDengine/build" should yield 3
- numSegments = numSegments - 1 # DEBUG only
- env['GCOV_PREFIX'] = bPath + '/svc_gcov'
+ numSegments = len(bPath.split('/')) # "/x/TDengine/build" should yield 3
+ # numSegments += 2 # cover "/src" after build
+ # numSegments = numSegments - 1 # DEBUG only
+ env['GCOV_PREFIX'] = bPath + '/src_s' # Server side source
env['GCOV_PREFIX_STRIP'] = str(numSegments) # Strip every element, plus, ENV needs strings
+ # VERY VERY important note: GCOV data collection NOT effective upon SIG_KILL
Logging.info("Preparing GCOV environement to strip {} elements and use path: {}".format(
numSegments, env['GCOV_PREFIX'] ))
@@ -258,14 +260,15 @@ class TdeSubProcess:
TdeInstance.prepareGcovEnv(myEnv)
# print(myEnv)
- # print(myEnv.items())
+ # print("Starting TDengine with env: ", myEnv.items())
# print("Starting TDengine via Shell: {}".format(cmdLineStr))
useShell = True
self.subProcess = subprocess.Popen(
- ' '.join(cmdLine) if useShell else cmdLine,
- shell=useShell,
- # svcCmdSingle, shell=True, # capture core dump?
+ # ' '.join(cmdLine) if useShell else cmdLine,
+ # shell=useShell,
+ ' '.join(cmdLine),
+ shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
# bufsize=1, # not supported in binary mode
@@ -273,7 +276,8 @@ class TdeSubProcess:
env=myEnv
) # had text=True, which interferred with reading EOF
- STOP_SIGNAL = signal.SIGKILL # What signal to use (in kill) to stop a taosd process?
+ STOP_SIGNAL = signal.SIGKILL # signal.SIGKILL/SIGINT # What signal to use (in kill) to stop a taosd process?
+ SIG_KILL_RETCODE = 137 # ref: https://stackoverflow.com/questions/43268156/process-finished-with-exit-code-137-in-pycharm
def stop(self):
"""
@@ -320,8 +324,12 @@ class TdeSubProcess:
retCode = self.subProcess.returncode # should always be there
# May throw subprocess.TimeoutExpired exception above, therefore
# The process is guranteed to have ended by now
- self.subProcess = None
- if retCode != 0: # != (- signal.SIGINT):
+ self.subProcess = None
+ if retCode == self.SIG_KILL_RETCODE:
+ Logging.info("TSP.stop(): sub proc KILLED, as expected")
+ elif retCode == (- self.STOP_SIGNAL):
+ Logging.info("TSP.stop(), sub process STOPPED, as expected")
+ elif retCode != 0: # != (- signal.SIGINT):
Logging.error("TSP.stop(): Failed to stop sub proc properly w/ SIG {}, retCode={}".format(
self.STOP_SIGNAL, retCode))
else:
diff --git a/tests/pytest/fulltest.sh b/tests/pytest/fulltest.sh
index 0e3b482e3da2c6618edd64c5dd004e8812078d99..042fd826e8c81653d719b9b444df1bd8ee5af3cb 100755
--- a/tests/pytest/fulltest.sh
+++ b/tests/pytest/fulltest.sh
@@ -19,6 +19,7 @@ python3 ./test.py -f insert/randomNullCommit.py
python3 insert/retentionpolicy.py
python3 ./test.py -f insert/alterTableAndInsert.py
python3 ./test.py -f insert/insertIntoTwoTables.py
+python3 ./test.py -f insert/before_1970.py
python3 ./test.py -f table/alter_wal0.py
python3 ./test.py -f table/column_name.py
@@ -228,6 +229,7 @@ python3 ./test.py -f update/merge_commit_data2.py
python3 ./test.py -f update/merge_commit_data2_update0.py
python3 ./test.py -f update/merge_commit_last-0.py
python3 ./test.py -f update/merge_commit_last.py
+python3 ./test.py -f update/bug_td2279.py
# wal
python3 ./test.py -f wal/addOldWalTest.py
\ No newline at end of file
diff --git a/tests/pytest/hivemq-extension-test.py b/tests/pytest/hivemq-extension-test.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b1ef83fe5841826ad0ab80384b5320662e104
--- /dev/null
+++ b/tests/pytest/hivemq-extension-test.py
@@ -0,0 +1,249 @@
+#!/usr/bin/python3
+###################################################################
+# Copyright (c) 2016 by TAOS Technologies, Inc.
+# All rights reserved.
+#
+# This file is proprietary and confidential to TAOS Technologies.
+# No part of this file may be reproduced, stored, transmitted,
+# disclosed or used in any form or by any means other than as
+# expressly provided by the written permission from Jianhui Tao
+#
+###################################################################
+# install pip
+# pip install src/connector/python/linux/python2/
+import sys
+import os
+import os.path
+import time
+import glob
+import getopt
+import subprocess
+from shutil import which
+from multipledispatch import dispatch
+
+
+@dispatch(str, str)
+def v_print(msg: str, arg: str):
+ if verbose:
+ print(msg % arg)
+
+
+@dispatch(str, int)
+def v_print(msg: str, arg: int):
+ if verbose:
+ print(msg % int(arg))
+
+
+@dispatch(str, int, int)
+def v_print(msg: str, arg1: int, arg2: int):
+ if verbose:
+ print(msg % (int(arg1), int(arg2)))
+
+
+@dispatch(str, int, int, int)
+def v_print(msg: str, arg1: int, arg2: int, arg3: int):
+ if verbose:
+ print(msg % (int(arg1), int(arg2), int(arg3)))
+
+
+@dispatch(str, int, int, int, int)
+def v_print(msg: str, arg1: int, arg2: int, arg3: int, arg4: int):
+ if verbose:
+ print(msg % (int(arg1), int(arg2), int(arg3), int(arg4)))
+
+
+def isHiveMQInstalled():
+ v_print("%s", "Check if HiveMQ installed")
+ defaultHiveMQPath = "/opt/hivemq*"
+ hiveMQDir = glob.glob(defaultHiveMQPath)
+ if (len(hiveMQDir) == 0):
+ v_print("%s", "ERROR: HiveMQ NOT found")
+ return False
+ else:
+ v_print("HiveMQ installed at %s", hiveMQDir[0])
+ return True
+
+
+def isMosquittoInstalled():
+ v_print("%s", "Check if mosquitto installed")
+ if not which('mosquitto_pub'):
+ v_print("%s", "ERROR: mosquitto is NOT installed")
+ return False
+ else:
+ return True
+
+
+def installExtension():
+ currentDir = os.getcwd()
+ extDir = 'src/connector/hivemq-tdengine-extension'
+ os.chdir('../..')
+ os.system('git submodule update --init -- %s' % extDir)
+ os.chdir(extDir)
+ v_print("%s", "build extension..")
+ os.system('mvn clean package')
+
+ tdExtensionZip = 'target/hivemq-tdengine-extension*.zip'
+ tdExtensionZipDir = glob.glob(tdExtensionZip)
+
+ defaultHiveMQPath = "/opt/hivemq*"
+ hiveMQDir = glob.glob(defaultHiveMQPath)
+ extPath = hiveMQDir[0] + '/extensions'
+
+ tdExtDir = glob.glob(extPath + '/hivemq-tdengine-extension')
+ if len(tdExtDir):
+ v_print("%s", "delete exist extension..")
+ os.system('rm -rf %s' % tdExtDir[0])
+
+ v_print("%s", "unzip extension..")
+ os.system('unzip %s -d %s' % (tdExtensionZipDir[0], extPath))
+
+ os.chdir(currentDir)
+
+
+def stopProgram(prog: str):
+ psCmd = "ps ax|grep -w %s| grep -v grep | awk '{print $1}'" % prog
+
+ processID = subprocess.check_output(
+ psCmd, shell=True).decode("utf-8")
+
+ while(processID):
+ killCmd = "kill -TERM %s > /dev/null 2>&1" % processID
+ os.system(killCmd)
+ time.sleep(1)
+ processID = subprocess.check_output(
+ psCmd, shell=True).decode("utf-8")
+ pass
+
+
+def stopHiveMQ():
+ stopProgram("hivemq.jar")
+ v_print("%s", "ERROR: HiveMQ is NOT running")
+
+
+def checkProgramRunning(prog: str):
+ psCmd = "ps ax|grep -w %s| grep -v grep | awk '{print $1}'" % prog
+
+ processID = subprocess.check_output(
+ psCmd, shell=True).decode("utf-8")
+
+ if not processID:
+ v_print("ERROR: %s is NOT running", prog)
+ return False
+ else:
+ return True
+
+
+def runHiveMQ():
+ defaultHiveMQPath = "/opt/hivemq*"
+ hiveMQDir = glob.glob(defaultHiveMQPath)
+ runPath = hiveMQDir[0] + '/bin/run.sh > /dev/null &'
+ os.system(runPath)
+ time.sleep(10)
+
+ if not checkProgramRunning("hivemq.jar"):
+ return False
+ else:
+ v_print("%s", "hivemq is running")
+ return True
+
+
+def getBuildPath():
+ selfPath = os.path.dirname(os.path.realpath(__file__))
+
+ binPath = ''
+
+ if ("community" in selfPath):
+ projPath = selfPath[:selfPath.find("community")]
+ else:
+ projPath = selfPath[:selfPath.find("tests")]
+
+ for root, dirs, files in os.walk(projPath):
+ if ("taosd" in files):
+ rootRealPath = os.path.dirname(os.path.realpath(root))
+ if ("packaging" not in rootRealPath):
+ binPath = root[:len(root) - len("/build/bin")]
+ break
+ return binPath
+
+
+def runTDengine():
+ stopProgram("taosd")
+
+ buildPath = getBuildPath()
+
+ if (buildPath == ""):
+ v_print("%s", "ERROR: taosd NOT found!")
+ sys.exit(1)
+ else:
+ v_print("%s", "taosd found in %s" % buildPath)
+
+ binPath = buildPath + "/build/bin/taosd"
+
+ os.system('%s > /dev/null &' % binPath)
+ time.sleep(10)
+ if not checkProgramRunning("taosd"):
+ return False
+ else:
+ v_print("%s", "TDengine is running")
+ return True
+
+
+
+def reCreateDatabase():
+ buildPath = getBuildPath()
+ binPath = buildPath + "/build/bin/taos"
+
+ os.system('%s -s "DROP DATABASE IF EXISTS hivemq"' % binPath)
+ os.system('%s -s "CREATE DATABASE IF NOT EXISTS hivemq"' % binPath)
+
+
+def sendMqttMsg(topic: str, payload: str):
+ testStr = 'mosquitto_pub -t %s -m "%s"' % (topic, payload)
+ os.system(testStr)
+ time.sleep(3)
+
+
+def checkTDengineData(topic: str, payload: str):
+ buildPath = getBuildPath()
+ binPath = buildPath + "/build/bin/taos"
+
+ output = subprocess.check_output(
+ '%s -s "select * from hivemq.mqtt_payload"' %
+ binPath, shell=True).decode('utf-8')
+ if (topic in output) and (payload in output):
+ v_print("%s", output)
+ return True
+ else:
+ v_print("%s", "ERROR: mqtt topic or payload NOT found")
+ return False
+
+
+if __name__ == "__main__":
+ verbose = True
+ testTopic = 'test'
+ testPayload = 'hello world'
+
+ if not isHiveMQInstalled():
+ sys.exit(1)
+
+ if not isMosquittoInstalled():
+ sys.exit(1)
+
+ stopHiveMQ()
+
+ installExtension()
+
+ if not runTDengine():
+ sys.exit(1)
+
+ reCreateDatabase()
+
+ if not runHiveMQ():
+ sys.exit(1)
+
+ sendMqttMsg(testTopic, testPayload)
+
+ if not checkTDengineData(testTopic, testPayload):
+ sys.exit(1)
+
+ sys.exit(0)
diff --git a/tests/pytest/insert/insertDemo.py b/tests/pytest/insert/insertDemo.py
new file mode 100644
index 0000000000000000000000000000000000000000..d18206e7a46b960499263b2960a7e3a42ff806ca
--- /dev/null
+++ b/tests/pytest/insert/insertDemo.py
@@ -0,0 +1,47 @@
+import taos
+import datetime
+import random
+import multiprocessing
+
+def taos_excute(table, connect_host):
+ conn = taos.connect(host=connect_host, user="root", password="taosdata", config="/etc/taos", database='test')
+ cursor = conn.cursor()
+ for i in range(1000000):
+ pk = random.randint(100001, 300000)
+ time_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
+ col1 = random.randint(1, 10000)
+ col2 = random.randint(1, 10000)
+ col3 = random.randint(1, 10000)
+ col4 = random.randint(1, 10000)
+ col5 = random.randint(1, 10000)
+ col6 = random.randint(1, 10000)
+ sql = f"INSERT INTO {table}_{pk} USING {table} TAGS ({pk}) VALUES ('{time_now}', {col1}, {col2}, {col3}, {col4}, {col5}, {col6})"
+ cursor.execute(sql)
+ cursor.close()
+ conn.close()
+
+def taos_init(table, connect_host, pk):
+ conn = taos.connect(host=connect_host, user="root", password="taosdata", config="/etc/taos", database='test')
+ cursor = conn.cursor()
+ sql = f"CREATE TABLE {table}_{pk} USING {table} TAGS ({pk})"
+ cursor.execute(sql)
+ cursor.close()
+ conn.close()
+
+print("init time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
+
+connect_list = ["node1", "node2", "node3", "node4", "node5"]
+pool = multiprocessing.Pool(processes=108)
+
+for pk in range(100001, 300000):
+ pool.apply_async(func=taos_init, args=("test", connect_list[pk % 5], pk, ))
+
+print("start time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
+
+for i in range(10000):
+ pool.apply_async(func=taos_excute, args=("test", connect_list[i % 5],))
+
+pool.close()
+pool.join()
+
+print("end time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
\ No newline at end of file
diff --git a/tests/pytest/insert/insertFromCSVOurofOrder.py b/tests/pytest/insert/insertFromCSVOurofOrder.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4de85b7e93e78ad12962c54fbd1014615dc8e3b
--- /dev/null
+++ b/tests/pytest/insert/insertFromCSVOurofOrder.py
@@ -0,0 +1,71 @@
+###################################################################
+# Copyright (c) 2016 by TAOS Technologies, Inc.
+# All rights reserved.
+#
+# This file is proprietary and confidential to TAOS Technologies.
+# No part of this file may be reproduced, stored, transmitted,
+# disclosed or used in any form or by any means other than as
+# expressly provided by the written permission from Jianhui Tao
+#
+###################################################################
+
+# -*- coding: utf-8 -*-
+
+import sys
+import taos
+from util.log import tdLog
+from util.cases import tdCases
+from util.sql import tdSql
+import time
+import datetime
+import csv
+import random
+import pandas as pd
+
+
+class TDTestCase:
+ def init(self, conn, logSql):
+ tdLog.debug("start to execute %s" % __file__)
+ tdSql.init(conn.cursor(), logSql)
+
+ self.ts = 1500074556514
+
+ def writeCSV(self):
+ with open('test3.csv','w', encoding='utf-8', newline='') as csvFile:
+ writer = csv.writer(csvFile, dialect='excel')
+ for i in range(1000000):
+ newTimestamp = self.ts + random.randint(10000000, 10000000000) + random.randint(1000, 10000000) + random.randint(1, 1000)
+ d = datetime.datetime.fromtimestamp(newTimestamp / 1000)
+ dt = str(d.strftime("%Y-%m-%d %H:%M:%S.%f"))
+ writer.writerow(["'%s'" % dt, random.randint(1, 100), random.uniform(1, 100), random.randint(1, 100), random.randint(1, 100)])
+
+ def removCSVHeader(self):
+ data = pd.read_csv("ordered.csv")
+ data = data.drop([0])
+ data.to_csv("ordered.csv", header = False, index = False)
+
+ def run(self):
+ tdSql.prepare()
+
+ tdSql.execute("create table t1(ts timestamp, c1 int, c2 float, c3 int, c4 int)")
+ startTime = time.time()
+ tdSql.execute("insert into t1 file 'outoforder.csv'")
+ duration = time.time() - startTime
+ print("Out of Order - Insert time: %d" % duration)
+ tdSql.query("select count(*) from t1")
+ rows = tdSql.getData(0, 0)
+
+ tdSql.execute("create table t2(ts timestamp, c1 int, c2 float, c3 int, c4 int)")
+ startTime = time.time()
+ tdSql.execute("insert into t2 file 'ordered.csv'")
+ duration = time.time() - startTime
+ print("Ordered - Insert time: %d" % duration)
+ tdSql.query("select count(*) from t2")
+ tdSql.checkData(0,0, rows)
+
+ def stop(self):
+ tdSql.close()
+ tdLog.success("%s successfully executed" % __file__)
+
+tdCases.addWindows(__file__, TDTestCase())
+tdCases.addLinux(__file__, TDTestCase())
\ No newline at end of file
diff --git a/tests/pytest/insert/restfulInsert.py b/tests/pytest/insert/restfulInsert.py
index e3a963f1d41805656ccab619ea52da751fa4dbb0..da797f788fcc3cc1ae06843b70da9aaf7230e97c 100644
--- a/tests/pytest/insert/restfulInsert.py
+++ b/tests/pytest/insert/restfulInsert.py
@@ -18,7 +18,7 @@ import time
import argparse
class RestfulInsert:
- def __init__(self, host, startTimestamp, dbname, threads, tables, records, batchSize, tbNamePerfix, outOfOrder):
+ def __init__(self, host, startTimestamp, dbname, threads, tables, records, batchSize, tbNamePerfix, outOfOrder,tablePerbatch):
self.header = {'Authorization': 'Basic cm9vdDp0YW9zZGF0YQ=='}
self.url = "http://%s:6041/rest/sql" % host
self.ts = startTimestamp
@@ -29,32 +29,71 @@ class RestfulInsert:
self.batchSize = batchSize
self.tableNamePerfix = tbNamePerfix
self.outOfOrder = outOfOrder
+ self.tablePerbatch = tablePerbatch
def createTable(self, threadID):
- tablesPerThread = int (self.numOfTables / self.numOfThreads)
- print("create table %d to %d" % (tablesPerThread * threadID, tablesPerThread * (threadID + 1) - 1))
- for i in range(tablesPerThread):
+ tablesPerThread = int (self.numOfTables / self.numOfThreads)
+ loop = tablesPerThread if threadID != self.numOfThreads - 1 else self.numOfTables - tablesPerThread * threadID
+ print("create table %d to %d" % (tablesPerThread * threadID, tablesPerThread * threadID + loop - 1))
+ for i in range(loop):
tableID = threadID * tablesPerThread
+ if tableID + i >= self.numOfTables : break
name = 'beijing' if tableID % 2 == 0 else 'shanghai'
data = "create table if not exists %s.%s%d using %s.meters tags(%d, '%s')" % (self.dbname, self.tableNamePerfix, tableID + i, self.dbname, tableID + i, name)
response = requests.post(self.url, data, headers = self.header)
if response.status_code != 200:
print(response.content)
+
+
def insertData(self, threadID):
print("thread %d started" % threadID)
- tablesPerThread = int (self.numOfTables / self.numOfThreads)
- for i in range(tablesPerThread):
- tableID = i + threadID * tablesPerThread
- start = self.ts
- for j in range(int(self.recordsPerTable / self.batchSize)):
- data = "insert into %s.%s%d values" % (self.dbname, self.tableNamePerfix, tableID)
- values = []
- for k in range(self.batchSize):
- data += "(%d, %d, %d, %d)" % (start + j * self.batchSize + k, random.randint(1, 100), random.randint(1, 100), random.randint(1, 100))
- response = requests.post(self.url, data, headers = self.header)
- if response.status_code != 200:
- print(response.content)
+ tablesPerThread = int (self.numOfTables / self.numOfThreads)
+ loop = int(self.recordsPerTable / self.batchSize)
+ if self.tablePerbatch == 1 :
+ for i in range(tablesPerThread+1):
+ tableID = i + threadID * tablesPerThread
+ if tableID >= self.numOfTables: return
+ start = self.ts
+ start1=time.time()
+ for k in range(loop):
+ data = "insert into %s.%s%d values" % (self.dbname, self.tableNamePerfix, tableID)
+ values = []
+ bloop = self.batchSize if k != loop - 1 else self.recordsPerTable - self.batchSize * k
+ for l in range(bloop):
+ values.append("(%d, %d, %d, %d)" % (start + k * self.batchSize + l, random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)))
+ if len(data) > 1048576 :
+ print ('batch size is larger than 1M')
+ exit(-1)
+ if self.outOfOrder :
+ random.shuffle(values)
+ data+=''.join(values)
+ response = requests.post(self.url, data, headers = self.header)
+ if response.status_code != 200:
+ print(response.content)
+ else:
+ for i in range(0,tablesPerThread+self.tablePerbatch,self.tablePerbatch):
+ for k in range(loop):
+ data = "insert into "
+ for j in range(self.tablePerbatch):
+ tableID = i + threadID * tablesPerThread+j
+ if tableID >= self.numOfTables: return
+ start = self.ts
+ data += "%s.%s%d values" % (self.dbname, self.tableNamePerfix, tableID)
+ values = []
+ bloop = self.batchSize if k != loop - 1 else self.recordsPerTable - self.batchSize * k
+ for l in range(bloop):
+ values.append("(%d, %d, %d, %d)" % (start + k * self.batchSize + l, random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)))
+ if self.outOfOrder :
+ random.shuffle(values)
+ data+=''.join(values)
+ if len(data) > 1024*1024 :
+ print ('batch size is larger than 1M')
+ exit(-1)
+ response = requests.post(self.url, data, headers = self.header)
+ if response.status_code != 200:
+ print(response.content)
+
def insertUnlimitedData(self, threadID):
print("thread %d started" % threadID)
@@ -85,7 +124,7 @@ class RestfulInsert:
if response.status_code != 200:
print(response.content)
- def run(self):
+ def run(self):
data = "create database if not exists %s" % self.dbname
requests.post(self.url, data, headers = self.header)
data = "create table if not exists %s.meters(ts timestamp, f1 int, f2 int, f3 int) tags(id int, loc nchar(20))" % self.dbname
@@ -114,7 +153,7 @@ class RestfulInsert:
for i in range(self.numOfThreads):
threads[i].join()
- print("inserting %d records takes %d seconds" % (self.numOfTables * self.recordsPerTable, (time.time() - startTime)))
+ print("inserting %s records takes %d seconds" % (self.numOfTables * self.recordsPerTable, (time.time() - startTime)))
parser = argparse.ArgumentParser()
parser.add_argument(
@@ -149,14 +188,14 @@ parser.add_argument(
'-T',
'--number-of-tables',
action='store',
- default=1000,
+ default=10000,
type=int,
help='Number of tables to be created (default: 1000)')
parser.add_argument(
'-r',
'--number-of-records',
action='store',
- default=1000,
+ default=10000,
type=int,
help='Number of record to be created for each table (default: 1000, -1 for unlimited records)')
parser.add_argument(
@@ -178,7 +217,18 @@ parser.add_argument(
'--out-of-order',
action='store_true',
help='The order of test data (default: False)')
+parser.add_argument(
+ '-b',
+ '--table-per-batch',
+ action='store',
+ default=1,
+ type=int,
+ help='the table per batch (default: 1)')
+
+
args = parser.parse_args()
-ri = RestfulInsert(args.host_name, args.start_timestamp, args.db_name, args.number_of_threads, args.number_of_tables, args.number_of_records, args.batch_size, args.table_name_prefix, args.out_of_order)
+ri = RestfulInsert(
+ args.host_name, args.start_timestamp, args.db_name, args.number_of_threads, args.number_of_tables,
+ args.number_of_records, args.batch_size, args.table_name_prefix, args.out_of_order, args.table_per_batch)
ri.run()
\ No newline at end of file
diff --git a/tests/pytest/pytest_1.sh b/tests/pytest/pytest_1.sh
new file mode 100755
index 0000000000000000000000000000000000000000..52f5a30f4e83089bc2e6f230c099e4304a94efd4
--- /dev/null
+++ b/tests/pytest/pytest_1.sh
@@ -0,0 +1,218 @@
+#!/bin/bash
+ulimit -c unlimited
+
+python3 ./test.py -f insert/basic.py
+python3 ./test.py -f insert/int.py
+python3 ./test.py -f insert/float.py
+python3 ./test.py -f insert/bigint.py
+python3 ./test.py -f insert/bool.py
+python3 ./test.py -f insert/double.py
+python3 ./test.py -f insert/smallint.py
+python3 ./test.py -f insert/tinyint.py
+python3 ./test.py -f insert/date.py
+python3 ./test.py -f insert/binary.py
+python3 ./test.py -f insert/nchar.py
+#python3 ./test.py -f insert/nchar-boundary.py
+python3 ./test.py -f insert/nchar-unicode.py
+python3 ./test.py -f insert/multi.py
+python3 ./test.py -f insert/randomNullCommit.py
+python3 insert/retentionpolicy.py
+python3 ./test.py -f insert/alterTableAndInsert.py
+python3 ./test.py -f insert/insertIntoTwoTables.py
+
+python3 ./test.py -f table/alter_wal0.py
+python3 ./test.py -f table/column_name.py
+python3 ./test.py -f table/column_num.py
+python3 ./test.py -f table/db_table.py
+python3 ./test.py -f table/create_sensitive.py
+#python3 ./test.py -f table/tablename-boundary.py
+
+# tag
+python3 ./test.py -f tag_lite/filter.py
+python3 ./test.py -f tag_lite/create-tags-boundary.py
+python3 ./test.py -f tag_lite/3.py
+python3 ./test.py -f tag_lite/4.py
+python3 ./test.py -f tag_lite/5.py
+python3 ./test.py -f tag_lite/6.py
+python3 ./test.py -f tag_lite/add.py
+python3 ./test.py -f tag_lite/bigint.py
+python3 ./test.py -f tag_lite/binary_binary.py
+python3 ./test.py -f tag_lite/binary.py
+python3 ./test.py -f tag_lite/bool_binary.py
+python3 ./test.py -f tag_lite/bool_int.py
+python3 ./test.py -f tag_lite/bool.py
+python3 ./test.py -f tag_lite/change.py
+python3 ./test.py -f tag_lite/column.py
+python3 ./test.py -f tag_lite/commit.py
+python3 ./test.py -f tag_lite/create.py
+python3 ./test.py -f tag_lite/datatype.py
+python3 ./test.py -f tag_lite/datatype-without-alter.py
+python3 ./test.py -f tag_lite/delete.py
+python3 ./test.py -f tag_lite/double.py
+python3 ./test.py -f tag_lite/float.py
+python3 ./test.py -f tag_lite/int_binary.py
+python3 ./test.py -f tag_lite/int_float.py
+python3 ./test.py -f tag_lite/int.py
+python3 ./test.py -f tag_lite/set.py
+python3 ./test.py -f tag_lite/smallint.py
+python3 ./test.py -f tag_lite/tinyint.py
+
+#python3 ./test.py -f dbmgmt/database-name-boundary.py
+
+python3 ./test.py -f import_merge/importBlock1HO.py
+python3 ./test.py -f import_merge/importBlock1HPO.py
+python3 ./test.py -f import_merge/importBlock1H.py
+python3 ./test.py -f import_merge/importBlock1S.py
+python3 ./test.py -f import_merge/importBlock1Sub.py
+python3 ./test.py -f import_merge/importBlock1TO.py
+python3 ./test.py -f import_merge/importBlock1TPO.py
+python3 ./test.py -f import_merge/importBlock1T.py
+python3 ./test.py -f import_merge/importBlock2HO.py
+python3 ./test.py -f import_merge/importBlock2HPO.py
+python3 ./test.py -f import_merge/importBlock2H.py
+python3 ./test.py -f import_merge/importBlock2S.py
+python3 ./test.py -f import_merge/importBlock2Sub.py
+python3 ./test.py -f import_merge/importBlock2TO.py
+python3 ./test.py -f import_merge/importBlock2TPO.py
+python3 ./test.py -f import_merge/importBlock2T.py
+python3 ./test.py -f import_merge/importBlockbetween.py
+python3 ./test.py -f import_merge/importCacheFileHO.py
+python3 ./test.py -f import_merge/importCacheFileHPO.py
+python3 ./test.py -f import_merge/importCacheFileH.py
+python3 ./test.py -f import_merge/importCacheFileS.py
+python3 ./test.py -f import_merge/importCacheFileSub.py
+python3 ./test.py -f import_merge/importCacheFileTO.py
+python3 ./test.py -f import_merge/importCacheFileTPO.py
+python3 ./test.py -f import_merge/importCacheFileT.py
+python3 ./test.py -f import_merge/importDataH2.py
+python3 ./test.py -f import_merge/importDataHO2.py
+python3 ./test.py -f import_merge/importDataHO.py
+python3 ./test.py -f import_merge/importDataHPO.py
+python3 ./test.py -f import_merge/importDataLastHO.py
+python3 ./test.py -f import_merge/importDataLastHPO.py
+python3 ./test.py -f import_merge/importDataLastH.py
+python3 ./test.py -f import_merge/importDataLastS.py
+python3 ./test.py -f import_merge/importDataLastSub.py
+python3 ./test.py -f import_merge/importDataLastTO.py
+python3 ./test.py -f import_merge/importDataLastTPO.py
+python3 ./test.py -f import_merge/importDataLastT.py
+python3 ./test.py -f import_merge/importDataS.py
+python3 ./test.py -f import_merge/importDataSub.py
+python3 ./test.py -f import_merge/importDataTO.py
+python3 ./test.py -f import_merge/importDataTPO.py
+python3 ./test.py -f import_merge/importDataT.py
+python3 ./test.py -f import_merge/importHeadOverlap.py
+python3 ./test.py -f import_merge/importHeadPartOverlap.py
+python3 ./test.py -f import_merge/importHead.py
+python3 ./test.py -f import_merge/importHORestart.py
+python3 ./test.py -f import_merge/importHPORestart.py
+python3 ./test.py -f import_merge/importHRestart.py
+python3 ./test.py -f import_merge/importLastHO.py
+python3 ./test.py -f import_merge/importLastHPO.py
+python3 ./test.py -f import_merge/importLastH.py
+python3 ./test.py -f import_merge/importLastS.py
+python3 ./test.py -f import_merge/importLastSub.py
+python3 ./test.py -f import_merge/importLastTO.py
+python3 ./test.py -f import_merge/importLastTPO.py
+python3 ./test.py -f import_merge/importLastT.py
+python3 ./test.py -f import_merge/importSpan.py
+python3 ./test.py -f import_merge/importSRestart.py
+python3 ./test.py -f import_merge/importSubRestart.py
+python3 ./test.py -f import_merge/importTailOverlap.py
+python3 ./test.py -f import_merge/importTailPartOverlap.py
+python3 ./test.py -f import_merge/importTail.py
+python3 ./test.py -f import_merge/importToCommit.py
+python3 ./test.py -f import_merge/importTORestart.py
+python3 ./test.py -f import_merge/importTPORestart.py
+python3 ./test.py -f import_merge/importTRestart.py
+python3 ./test.py -f import_merge/importInsertThenImport.py
+python3 ./test.py -f import_merge/importCSV.py
+# user
+python3 ./test.py -f user/user_create.py
+python3 ./test.py -f user/pass_len.py
+
+# stable
+python3 ./test.py -f stable/query_after_reset.py
+
+# table
+python3 ./test.py -f table/del_stable.py
+
+#query
+python3 ./test.py -f query/filter.py
+python3 ./test.py -f query/filterCombo.py
+python3 ./test.py -f query/queryNormal.py
+python3 ./test.py -f query/queryError.py
+python3 ./test.py -f query/filterAllIntTypes.py
+python3 ./test.py -f query/filterFloatAndDouble.py
+python3 ./test.py -f query/filterOtherTypes.py
+python3 ./test.py -f query/querySort.py
+python3 ./test.py -f query/queryJoin.py
+python3 ./test.py -f query/select_last_crash.py
+python3 ./test.py -f query/queryNullValueTest.py
+python3 ./test.py -f query/queryInsertValue.py
+python3 ./test.py -f query/queryConnection.py
+python3 ./test.py -f query/queryCountCSVData.py
+python3 ./test.py -f query/natualInterval.py
+python3 ./test.py -f query/bug1471.py
+#python3 ./test.py -f query/dataLossTest.py
+python3 ./test.py -f query/bug1874.py
+python3 ./test.py -f query/bug1875.py
+python3 ./test.py -f query/bug1876.py
+python3 ./test.py -f query/bug2218.py
+
+#stream
+python3 ./test.py -f stream/metric_1.py
+python3 ./test.py -f stream/new.py
+python3 ./test.py -f stream/stream1.py
+python3 ./test.py -f stream/stream2.py
+#python3 ./test.py -f stream/parser.py
+python3 ./test.py -f stream/history.py
+
+#alter table
+python3 ./test.py -f alter/alter_table_crash.py
+
+# client
+python3 ./test.py -f client/client.py
+python3 ./test.py -f client/version.py
+python3 ./test.py -f client/alterDatabase.py
+
+# Misc
+python3 testCompress.py
+python3 testNoCompress.py
+python3 testMinTablesPerVnode.py
+
+# functions
+python3 ./test.py -f functions/function_avg.py -r 1
+python3 ./test.py -f functions/function_bottom.py -r 1
+python3 ./test.py -f functions/function_count.py -r 1
+python3 ./test.py -f functions/function_diff.py -r 1
+python3 ./test.py -f functions/function_first.py -r 1
+python3 ./test.py -f functions/function_last.py -r 1
+python3 ./test.py -f functions/function_last_row.py -r 1
+python3 ./test.py -f functions/function_leastsquares.py -r 1
+python3 ./test.py -f functions/function_max.py -r 1
+python3 ./test.py -f functions/function_min.py -r 1
+python3 ./test.py -f functions/function_operations.py -r 1
+python3 ./test.py -f functions/function_percentile.py -r 1
+python3 ./test.py -f functions/function_spread.py -r 1
+python3 ./test.py -f functions/function_stddev.py -r 1
+python3 ./test.py -f functions/function_sum.py -r 1
+python3 ./test.py -f functions/function_top.py -r 1
+#python3 ./test.py -f functions/function_twa.py -r 1
+python3 queryCount.py
+python3 ./test.py -f query/queryGroupbyWithInterval.py
+python3 client/twoClients.py
+python3 test.py -f query/queryInterval.py
+python3 test.py -f query/queryFillTest.py
+
+# tools
+python3 test.py -f tools/taosdemoTest.py
+python3 test.py -f tools/taosdumpTest.py
+python3 test.py -f tools/lowaTest.py
+
+# subscribe
+python3 test.py -f subscribe/singlemeter.py
+#python3 test.py -f subscribe/stability.py
+python3 test.py -f subscribe/supertable.py
+
+
diff --git a/tests/pytest/pytest_2.sh b/tests/pytest/pytest_2.sh
new file mode 100755
index 0000000000000000000000000000000000000000..fededea3bb34481aa34c37d4a802ba183494e491
--- /dev/null
+++ b/tests/pytest/pytest_2.sh
@@ -0,0 +1,17 @@
+
+
+# update
+python3 ./test.py -f update/allow_update.py
+python3 ./test.py -f update/allow_update-0.py
+python3 ./test.py -f update/append_commit_data.py
+python3 ./test.py -f update/append_commit_last-0.py
+python3 ./test.py -f update/append_commit_last.py
+python3 ./test.py -f update/merge_commit_data.py
+python3 ./test.py -f update/merge_commit_data-0.py
+python3 ./test.py -f update/merge_commit_data2.py
+python3 ./test.py -f update/merge_commit_data2_update0.py
+python3 ./test.py -f update/merge_commit_last-0.py
+python3 ./test.py -f update/merge_commit_last.py
+
+# wal
+python3 ./test.py -f wal/addOldWalTest.py
\ No newline at end of file
diff --git a/tests/pytest/query/bug2117.py b/tests/pytest/query/bug2117.py
new file mode 100644
index 0000000000000000000000000000000000000000..1158b78a2a05695065bed73179fdeb9257a2429a
--- /dev/null
+++ b/tests/pytest/query/bug2117.py
@@ -0,0 +1,50 @@
+###################################################################
+# Copyright (c) 2016 by TAOS Technologies, Inc.
+# All rights reserved.
+#
+# This file is proprietary and confidential to TAOS Technologies.
+# No part of this file may be reproduced, stored, transmitted,
+# disclosed or used in any form or by any means other than as
+# expressly provided by the written permission from Jianhui Tao
+#
+###################################################################
+
+# -*- coding: utf-8 -*-
+
+import sys
+from util.log import *
+from util.cases import *
+from util.sql import *
+from util.dnodes import *
+class TDTestCase:
+ def init(self, conn, logSql):
+ tdLog.debug("start to execute %s" % __file__)
+ tdSql.init(conn.cursor(), logSql)
+
+ def run(self):
+ tdSql.prepare()
+ print("==========step1")
+ print("create table && insert data")
+
+ tdSql.execute("create table mt0 (ts timestamp, c1 int, c2 float, c3 bigint, c4 smallint, c5 tinyint, c6 double, c7 bool,c8 binary(20),c9 nchar(20))")
+ insertRows = 1000
+ t0 = 1604298064000
+ tdLog.info("insert %d rows" % (insertRows))
+ for i in range(insertRows):
+ ret = tdSql.execute(
+ "insert into mt0 values (%d , %d,%d,%d,%d,%d,%d,%d,'%s','%s')" %
+ (t0+i,i%100,i/2,i%41,i%100,i%100,i*1.0,i%2,'taos'+str(i%100),'涛思'+str(i%100)))
+ print("==========step2")
+ print("test last with group by normal_col ")
+ tdSql.query('select last(c1) from mt0 group by c3')
+ tdSql.checkData(0,0,84)
+ tdSql.checkData(0,1,85)
+
+
+
+ def stop(self):
+ tdSql.close()
+ tdLog.success("%s successfully executed" % __file__)
+
+tdCases.addWindows(__file__, TDTestCase())
+tdCases.addLinux(__file__, TDTestCase())
\ No newline at end of file
diff --git a/tests/pytest/query/bug2218.py b/tests/pytest/query/bug2218.py
index bb92e5d9cee5baae0461cb97fd30de35acd0f5fb..080472383de905c74ca7680d2d7dddd7310daff5 100644
--- a/tests/pytest/query/bug2218.py
+++ b/tests/pytest/query/bug2218.py
@@ -38,12 +38,12 @@ class TDTestCase:
print("test col*1*1 desc ")
tdSql.query('select c1,c1*1*1,c2*1*1,c3*1*1,c4*1*1,c5*1*1,c6*1*1 from mt0 order by ts desc limit 2')
tdSql.checkData(0,0,99)
- tdSql.checkData(0,1,0.0)
- tdSql.checkData(0,2,0.0)
- tdSql.checkData(0,3,0.0)
- tdSql.checkData(0,4,0.0)
- tdSql.checkData(0,5,0.0)
- tdSql.checkData(0,6,0.0)
+ tdSql.checkData(0,1,99.0)
+ tdSql.checkData(0,2,499.0)
+ tdSql.checkData(0,3,99.0)
+ tdSql.checkData(0,4,99.0)
+ tdSql.checkData(0,5,99.0)
+ tdSql.checkData(0,6,999.0)
def stop(self):
diff --git a/tests/pytest/update/bug_td2279.py b/tests/pytest/update/bug_td2279.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e8640dfa09bc904cd49fe88da29bc306fdde6d0
--- /dev/null
+++ b/tests/pytest/update/bug_td2279.py
@@ -0,0 +1,67 @@
+###################################################################
+# Copyright (c) 2016 by TAOS Technologies, Inc.
+# All rights reserved.
+#
+# This file is proprietary and confidential to TAOS Technologies.
+# No part of this file may be reproduced, stored, transmitted,
+# disclosed or used in any form or by any means other than as
+# expressly provided by the written permission from Jianhui Tao
+#
+###################################################################
+
+# -*- coding: utf-8 -*-
+
+import sys
+import taos
+from util.log import *
+from util.cases import *
+from util.sql import *
+from util.dnodes import *
+
+
+class TDTestCase:
+ def init(self, conn, logSql):
+ tdLog.debug("start to execute %s" % __file__)
+ tdSql.init(conn.cursor())
+
+ self.ts = 1606700000000
+
+ def restartTaosd(self):
+ tdDnodes.stop(1)
+ tdDnodes.startWithoutSleep(1)
+ tdSql.execute("use db")
+
+ def run(self):
+ tdSql.prepare()
+
+ print("==============step1")
+ tdSql.execute("create table t (ts timestamp, a int)")
+
+ for i in range(3276):
+ tdSql.execute("insert into t values(%d, 0)" % (self.ts + i))
+
+ newTs = 1606700010000
+ for i in range(3275):
+ tdSql.execute("insert into t values(%d, 0)" % (self.ts + i))
+ tdSql.execute("insert into t values(%d, 0)" % 1606700013280)
+
+ self.restartTaosd()
+
+ for i in range(1606700003275, 1606700006609):
+ tdSql.execute("insert into t values(%d, 0)" % i)
+ tdSql.execute("insert into t values(%d, 0)" % 1606700006612)
+
+ self.restartTaosd()
+
+ tdSql.execute("insert into t values(%d, 0)" % 1606700006610)
+ tdSql.query("select * from t")
+ tdSql.checkRows(6612)
+
+ tdDnodes.stop(1)
+
+ def stop(self):
+ tdSql.close()
+ tdLog.success("%s successfully executed" % __file__)
+
+tdCases.addWindows(__file__, TDTestCase())
+tdCases.addLinux(__file__, TDTestCase())
diff --git a/tests/script/general/db/alter_option.sim b/tests/script/general/db/alter_option.sim
index c8aa2480c509353ede3c6ce6269afa9e6efd62b5..1c3f543ffdb149d67cfaf1527a0e88f46f626913 100644
--- a/tests/script/general/db/alter_option.sim
+++ b/tests/script/general/db/alter_option.sim
@@ -115,31 +115,31 @@ if $data7_db != 20,20,20 then
return -1
endi
-sql alter database db keep 10
+sql alter database db keep 20
sql show databases
print keep $data7_db
-if $data7_db != 20,20,10 then
+if $data7_db != 20,20,20 then
return -1
endi
-sql alter database db keep 20
+sql alter database db keep 30
sql show databases
print keep $data7_db
-if $data7_db != 20,20,20 then
+if $data7_db != 20,20,30 then
return -1
endi
-sql alter database db keep 30
+sql alter database db keep 40
sql show databases
print keep $data7_db
-if $data7_db != 20,20,30 then
+if $data7_db != 20,20,40 then
return -1
endi
sql alter database db keep 40
sql alter database db keep 30
sql alter database db keep 20
-sql alter database db keep 10
+sql_error alter database db keep 10
sql_error alter database db keep 9
sql_error alter database db keep 1
sql alter database db keep 0
@@ -277,4 +277,4 @@ sql_error alter database db prec 'us'
print ============== step status
sql_error alter database db status 'delete'
-system sh/exec.sh -n dnode1 -s stop -x SIGINT
\ No newline at end of file
+system sh/exec.sh -n dnode1 -s stop -x SIGINT
diff --git a/tests/test-all.sh b/tests/test-all.sh
index 5897978bce6ab68255b07dd85b3c310526e90e15..14b649eddfe92e8c557f81d27a0d1b95b35602c3 100755
--- a/tests/test-all.sh
+++ b/tests/test-all.sh
@@ -137,6 +137,12 @@ if [ "$2" != "sim" ]; then
elif [ "$1" == "pytest" ]; then
echo "### run Python full test ###"
runPyCaseOneByOne fulltest.sh
+ elif [ "$1" == "p1" ]; then
+ echo "### run Python_1 test ###"
+ runPyCaseOneByOne pytest_1.sh
+ elif [ "$1" == "p2" ]; then
+ echo "### run Python_2 test ###"
+ runPyCaseOneByOne pytest_2.sh
elif [ "$1" == "b2" ] || [ "$1" == "b3" ]; then
exit $(($totalFailed + $totalPyFailed))
elif [ "$1" == "smoke" ] || [ -z "$1" ]; then