How-To-Run-Test-And-How-To-Add-New-Test-Case.md 7.1 KB
Newer Older
1
# Prepare development environment
2

3 4 5
```shell
sudo apt install build-essential cmake net-tools python-pip python-setuptools \
 python3-pip python3-setuptools valgrind psmisc curl
6

7
git clone https://github.com/taosdata/TDengine
8

9
cd TDengine
10

11
git submodule update --init --recursive
12

13
mkdir debug
14

15
cd debug
16

17
cmake .. -DBUILD_TOOLS=true -DBUILD_HTTP=false
18

19 20 21 22 23 24 25 26 27 28 29 30 31
make

sudo make install

cd ../tests

pip3 install -r requirements.txt
```

> Note: Both Python2 and Python3 are currently supported by the Python test
> framework. Since Python2 is no longer officially supported by Python Software
> Foundation since January 1, 2020, it is recommended that subsequent test case
> development be guaranteed to run correctly on Python3.
32
>
33 34
> For Python2, please consider being compatible if appropriate without
> additional burden.
35
>
36 37 38 39
> If you use some new Linux distribution like Ubuntu 20.04 which already do not
> include Python2, please do not install Python2-related packages.
>
> <https://nakedsecurity.sophos.com/2020/01/03/python-is-dead-long-live-python/> 
40

41
## How to run Python test suite
42

43 44
```
cd TDengine/tests/pytest
45

46 47
# for smoke test
./smoketest.sh
48

49 50
# for memory leak detection test with valgrind
./smoketest.sh -g
51

52 53 54
# for full test
./fulltest.sh
```
55

56 57 58 59 60 61 62 63 64 65 66 67
> Note1: TDengine daemon's configuration and data files are stored in
> \<TDengine\>/sim directory. As a historical design, it's same place with
> TSIM script. So after the TSIM script ran with sudo privilege, the directory
> has been used by TSIM then the python script cannot write it by a normal
> user. You need to remove the directory completely first before running the
> Python test case. We should consider using two different locations to store
> for TSIM and Python script.
>
> Note2: if you need to debug crash problem with a core dump, you need
> manually edit smoketest.sh or fulltest.sh to add "ulimit -c unlimited"
> before the script line. Then you can look for the core file in
> \<TDengine\>/tests/pytest after the program crash.
68

69
## How to add a new test case
70

71
### 1. TSIM test cases
72

73 74 75 76
TSIM was the testing framework has been used internally. Now it still be used
 to run the test cases we develop in the past as a legacy system. We are
 turning to use Python to develop new test case and are abandoning TSIM
 gradually.
77

78
### 2. Python test cases
79

80
#### 2.1 Add a new Python test case
81

82 83 84 85
Please refer to `TDengine/tests/pytest/insert/basic.py` to add a new
test case. The new test case must implement 3 functions, where `self.init()`
and `self.stop()` simply copy the contents of `insert/basic.py` and the test
logic is implemented in `self.run()`. You can refer to the code in the `util`
86 87
directory for more information.

88
#### 2.2 Edit smoketest.sh to add the path and filename of the new test case
89 90 91 92 93 94

Note: The Python test framework may continue to be improved in the future,
hopefully, to provide more functionality and ease of writing test cases. The
method of writing the test case above does not exclude that it will also be
affected.

95
#### 2.3 What test.py does in detail
96 97 98 99 100 101 102 103

test.py is the entry program for test case execution and monitoring.

test.py has the following functions.

\-f --file, Specifies the test case file name to be executed
-p --path, Specifies deployment path

104
\-m --master, Specifies the master server IP for cluster deployment
105 106 107 108 109 110 111
-c--cluster, test cluster function
-s--stop, terminates all running nodes

\-g--valgrind, load valgrind for memory leak detection test

\-h--help, display help

112
#### 2.4 What util/log.py does in detail
113

114 115 116 117
`log.py` is quite simple, the main thing is that you can print the output in
different colors as needed. The `success()` should be called for successful
test case execution and the `success()` will print green text. The `exit()` will
print red text and exit the program, `exit()` should be called for test
118 119
failure.

120
- util/log.py
121

122 123 124
```python
    def info(self, info):
        print("%s %s" % (datetime.datetime.now(), info))
125

126 127 128
    def sleep(self, sec):
        print("%s sleep %d seconds" % (datetime.datetime.now(), sec))
        time.sleep(sec)
129

130 131
    def debug(self, err):
        print("\\033[1;36m%s %s\\033[0m" % (datetime.datetime.now(), err))
132

133 134
    def success(self, info):
        printf("\\033[1;32m%s %s\\033[0m" % (datetime.datetime.now(), info))
135

136 137
    def notice(self, err):
        printf("\\033[1;33m%s %s\\033[0m" % (datetime.datetime.now(), err))
138

139 140 141
    def exit(self, err):
        printf("\\033[1;31m%s %s\\033[0m" % (datetime.datetime.now(), err))
        sys.exit(1)
142

143 144 145
    def printNoPrefix(self, info):
        printf("\\033[1;36m%s\\033[0m" % (info)
```
146

147
#### 2.5 What util/sql.py does in detail
148 149 150 151

SQL.py is mainly used to execute SQL statements to manipulate the database,
and the code is extracted and commented as follows:

152
- util/sql.py
153

154 155
\# `prepare()` is mainly used to set up the environment for testing table and
data, and to set up the database db for testing. do not call `prepare()` if you
156 157
need to test the database operation command.

158
```python
159
def prepare(self):
160 161 162 163 164 165
    tdLog.info("prepare database:db")
    self.cursor.execute('reset query cache')
    self.cursor.execute('drop database if exists db')
    self.cursor.execute('create database db')
    self.cursor.execute('use db')
```
166

167
\# `query()` is mainly used to execute select statements for normal syntax input
168

169
```python
170 171
def query(self, sql):

172
```
173

174
\# `error()` is mainly used to execute the select statement with the wrong syntax
175 176 177
input, the error will be caught as a reasonable behavior, if not caught it will
prove that the test failed

178
```python
179
def error()
180
```
181

182 183
\# `checkRows()` is used to check the number of returned lines after calling
`query(select ...)` after calling the `query(select ...)` to check the number of
184 185
rows of returned results.

186
```python
187
def checkRows(self, expectRows):
188
```
189

190 191
\# `checkData()` is used to check the returned result data after calling
`query(select ...)` after the `query(select ...)` is called, failure to meet
192 193
expectation is

194
```python
195
def checkData(self, row, col, data):
196
```
197

198 199
\# `getData()` returns the result data after calling `query(select ...)` to return
the resulting data after calling `query(select ...)`
200

201
```python
202
def getData(self, row, col):
203
```
204

205
\# `execute()` used to execute SQL command and return the number of affected rows
206

207
```python
208
def execute(self, sql):
209
```
210

211
\# `executeTimes()` Multiple executions of the same sql statement
212

213
```python
214
def executeTimes(self, sql, times):
215
```
216

217
\# `checkAffectedRows()` to check if the number of affected rows is as expected
218

219
```python
220
def checkAffectedRows(self, expectAffectedRows):
221
```
222

223
## CI submission adoption principle
224

225
- Every commit / PR compilation must pass. Currently, the warning is treated
226 227
    as an error, so the warning must also be resolved.

228
- Test cases that already exist must pass.
229

230
- Because CI is very important to support build and automatically test
231 232 233 234
    procedure, it is necessary to manually test the test case before adding it
    and do as many iterations as possible to ensure that the test case provides
    stable and reliable test results when added.

235 236 237
> Note: In the future, according to the requirements and test development
> progress will add stress testing, performance testing, code style,
> and other features based on functional testing.