Skip to content

Commit fa7efda

Browse files
authored
test: Add automated tests
Automate tests listed in the [README](https://github.com/zendtech/db2iengine/blob/master/README.md)
1 parent 3753068 commit fa7efda

10 files changed

+817
-0
lines changed

tests/README.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# ibmdb2i Tests
2+
3+
## Setup
4+
5+
```bash
6+
$ pip3 install -r requirements.txt
7+
8+
$ mysqld_safe &
9+
10+
$ mysql
11+
12+
MariaDB [(none)]> create database db2itest;
13+
MariaDB [(none)]> install plugin ibmdb2i soname "ha_ibmdb2i.so";
14+
MariaDB [(none)]> quit
15+
```
16+
17+
## Run tests
18+
19+
```bash
20+
$ pytest
21+
```
22+
23+
## Configure
24+
25+
- `DB2I_DB` - The database to use. Defaults to use `db2itest`.
26+
27+
- `DB2I_HOST` - The host to connect to. Defaults to use `localhost`.
28+
29+
- `DB2I_USER`- The user to connect as. Defaults to `root`.
30+
31+
- `DB2I_PASS` - The user's password. Defaults to `''`.
32+

tests/requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mysql-connector-python
2+
pytest

tests/test_binary.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import mysql.connector as mariadb
2+
import datetime
3+
from os import getenv
4+
5+
TABLE = getenv('DB2I_TABLE') or 'test'
6+
DB = getenv('DB2I_DB') or 'db2itest'
7+
HOST = getenv('DB2I_HOST') or '127.0.0.1'
8+
USER = getenv('DB2I_USER') or 'root'
9+
PASS = getenv('DB2I_PASS') or ''
10+
11+
def create_insert_select(fields, values):
12+
conn = mariadb.connect(user=USER, password=PASS, host=HOST, database=DB)
13+
cursor = conn.cursor()
14+
cursor.execute(f"DROP TABLE IF EXISTS {TABLE}")
15+
conn.commit()
16+
cursor.execute(f"CREATE TABLE {TABLE} ({fields}) engine=ibmdb2i")
17+
cursor.execute(f"INSERT INTO {TABLE} VALUES({values})")
18+
conn.commit()
19+
cursor.execute(f"SELECT HEX(x), HEX(y), HEX (z) FROM {TABLE}")
20+
data = cursor.fetchone()
21+
print(f'Data: {data}')
22+
cursor.execute(f"DROP TABLE {TABLE}")
23+
conn.commit()
24+
cursor.close()
25+
conn.close()
26+
return data
27+
28+
def test_tinyblob():
29+
data = create_insert_select('x tinyblob, y tinyblob, z tinyblob', "x'DEADBEEF', 'ABC', 'CBA'")
30+
assert data[0] == 'DEADBEEF'
31+
assert data[1] == '414243'
32+
assert data[2] == '434241'
33+
34+
def test_mediumblob():
35+
data = create_insert_select('x mediumblob, y mediumblob, z mediumblob',
36+
"x'DEADBEEF', x'BADC0FFEE0DDF00D', 'ABC'")
37+
assert data[0] == 'DEADBEEF'
38+
assert data[1] == 'BADC0FFEE0DDF00D'
39+
assert data[2] == 414243 # returned as number rather than string
40+
41+
def test_longblob():
42+
data = create_insert_select('x longblob, y longblob, z longblob',
43+
"'ABC', x'BADC0FFEE0DDF00D', x'DEADBEEF'")
44+
assert data[0] == 414243 # returned as number rather than string
45+
assert data[1] == 'BADC0FFEE0DDF00D'
46+
assert data[2] == 'DEADBEEF'
47+
48+
def test_blob():
49+
data = create_insert_select('x blob, y blob, z blob',
50+
"'ABC', b'1111111111111', x'DEADBEEF'")
51+
assert data[0] == 414243 # returned as number rather than string
52+
assert data[1] == '1FFF'
53+
assert data[2] == 'DEADBEEF'
54+
55+
def test_binary():
56+
data = create_insert_select('x binary(10), y binary(10), z binary(10)',
57+
"'1234567890', x'DEADBEEF', x'BADC0FFEE0DDF00D'")
58+
assert data[0] == '31323334353637383930'
59+
assert data[1] == 'DEADBEEF000000000000'
60+
assert data[2] == 'BADC0FFEE0DDF00D0000'
61+
62+
def test_varbinary():
63+
data = create_insert_select('x varbinary(10), y varbinary(10), z varbinary(10)',
64+
"'1234567890', x'DEADBEEF', x'BADC0FFEE0DDF00D'")
65+
assert data[0] == '31323334353637383930'
66+
assert data[1] == 'DEADBEEF'
67+
assert data[2] == 'BADC0FFEE0DDF00D'

tests/test_char.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import mysql.connector as mariadb
2+
from os import getenv
3+
4+
TABLE = getenv('DB2I_TABLE') or 'test'
5+
DB = getenv('DB2I_DB') or 'db2itest'
6+
HOST = getenv('DB2I_HOST') or '127.0.0.1'
7+
USER = getenv('DB2I_USER') or 'root'
8+
PASS = getenv('DB2I_PASS') or ''
9+
EXPECTED = getenv('DB2I_EXPECTED') or 'Hello World'
10+
11+
def create_insert_select(charset, collation="general_ci", expected=EXPECTED, encoding=None):
12+
collation = f'{charset}_{collation}'
13+
is_unicode = True if 'utf' in charset or 'ucs' in charset else False
14+
use_unicode = True if is_unicode else False
15+
conn_charset = 'utf8' if is_unicode else charset
16+
conn_collation = 'utf8_general_ci' if is_unicode else collation
17+
18+
conn = mariadb.connect(user=USER, password=PASS, host=HOST, database=DB,
19+
charset=conn_charset, collation=conn_collation, use_unicode=use_unicode)
20+
21+
cursor = conn.cursor()
22+
cursor.execute(f"DROP TABLE IF EXISTS {TABLE}")
23+
conn.commit()
24+
cursor.execute(f"CREATE TABLE {TABLE} (i char(255)) engine=ibmdb2i CHARACTER SET '{charset}' COLLATE '{collation}'")
25+
cursor.execute(f"INSERT INTO {TABLE} VALUES(%s)", (expected,))
26+
conn.commit()
27+
cursor.execute(f"SELECT i FROM {TABLE}")
28+
data = cursor.fetchone()
29+
if encoding:
30+
data = data[0].decode(encoding)
31+
else:
32+
data = data[0]
33+
34+
print(f'Data is: {data}')
35+
cursor.execute(f"DROP TABLE {TABLE}")
36+
conn.commit()
37+
cursor.close()
38+
conn.close()
39+
return data
40+
41+
def test_utf8():
42+
data = create_insert_select('utf8')
43+
assert data == EXPECTED
44+
45+
def test_utf8mb4():
46+
data = create_insert_select('utf8mb4')
47+
assert data == EXPECTED
48+
49+
def test_utf8mb3():
50+
data = create_insert_select('utf8mb3')
51+
assert data == EXPECTED
52+
53+
def test_utf16():
54+
data = create_insert_select('utf16')
55+
assert data == EXPECTED
56+
57+
def test_ucs2():
58+
data = create_insert_select('ucs2')
59+
assert data == EXPECTED
60+
61+
def test_ascii():
62+
# https://en.wikipedia.org/wiki/ASCII#Character_set
63+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F))]).decode('ascii')
64+
data = create_insert_select('ascii', expected=EXPECTED, encoding='ascii')
65+
assert data == EXPECTED
66+
67+
def test_latin1():
68+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-1#Code_page_layout
69+
# CCSID 1148 does not include ¤ (00A4) because its replaced by €
70+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
71+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-1')
72+
data = create_insert_select('latin1', expected=EXPECTED, encoding='iso8859-1')
73+
assert data == EXPECTED
74+
75+
def test_latin2():
76+
# CCSID 1153 does not include ¤ (00A4) because its replaced by €
77+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-2#Code_page_layout
78+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
79+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-2')
80+
data = create_insert_select('latin2', expected=EXPECTED, encoding='iso8859-2')
81+
assert data == EXPECTED
82+
83+
def test_greek():
84+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-7#Codepage_layout
85+
# CCSID 4971 does not support ₯ drachma sign (0XA5) and ͺ Greek ypogegrammeni (0XAA)
86+
# these are available in CCSID 9067 (March 2005) ?
87+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA5))
88+
+ tuple(range(0XA6, 0XAA)) + tuple(range(0XAB, 0XAE)) + tuple(range(0XAF, 0XD2))
89+
+ tuple(range(0XD4, 0XFF))]).decode('iso8859-7')
90+
data = create_insert_select('greek', expected=EXPECTED, encoding='iso8859-7')
91+
assert data == EXPECTED
92+
93+
def test_hebrew():
94+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-8#Codepage_layout
95+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA1))
96+
+ tuple(range(0XA2, 0XBF)) + tuple(range(0XDF, 0XFB))]).decode('iso8859-8')
97+
data = create_insert_select('hebrew', expected=EXPECTED, encoding='iso8859-8')
98+
assert data == EXPECTED
99+
100+
def test_latin5():
101+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-9#Codepage_layout
102+
# CCSID 1155 does not include ¤ (00A4) because its replaced by €
103+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
104+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-9')
105+
data = create_insert_select('latin5', 'turkish_ci', expected=EXPECTED, encoding='iso8859-9')
106+
assert data == EXPECTED
107+
108+
def test_tis620():
109+
# https://en.wikipedia.org/wiki/Thai_Industrial_Standard_620-2533#Character_set
110+
# The sole difference is that ISO/IEC 8859-11 allocates non-breaking space to code 0xA0,
111+
# while TIS-620 leaves it undefined. (In practice, this small distinction is usually ignored.)
112+
# Here we skip over nbsp 0xA0
113+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA1, 0XDB))
114+
+ tuple(range(0XDF, 0XFC))]).decode('iso8859-11')
115+
data = create_insert_select('tis620', 'thai_ci', expected=EXPECTED, encoding='iso8859-11')
116+
assert data == EXPECTED

tests/test_dates.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import mysql.connector as mariadb
2+
import datetime
3+
from os import getenv
4+
5+
TABLE = getenv('DB2I_TABLE') or 'test'
6+
DB = getenv('DB2I_DB') or 'db2itest'
7+
HOST = getenv('DB2I_HOST') or '127.0.0.1'
8+
USER = getenv('DB2I_USER') or 'root'
9+
PASS = getenv('DB2I_PASS') or ''
10+
11+
def create_insert_select(fields, values):
12+
conn = mariadb.connect(user=USER, password=PASS, host=HOST, database=DB)
13+
cursor = conn.cursor()
14+
cursor.execute(f"DROP TABLE IF EXISTS {TABLE}")
15+
conn.commit()
16+
cursor.execute(f"CREATE TABLE {TABLE} ({fields}) engine=ibmdb2i")
17+
cursor.execute(f"INSERT INTO {TABLE} VALUES({values})")
18+
conn.commit()
19+
cursor.execute(f"SELECT * FROM {TABLE}")
20+
data = cursor.fetchone()
21+
print(f'Data: {data}')
22+
cursor.execute(f"DROP TABLE {TABLE}")
23+
conn.commit()
24+
cursor.close()
25+
conn.close()
26+
return data
27+
28+
def test_date():
29+
data = create_insert_select('x date, y date, z date', "'2010-01-12', '120314', '13*04*21'")
30+
assert data[0] == datetime.date(2010, 1, 12)
31+
assert data[1] == datetime.date(2012, 3, 14)
32+
assert data[2] == datetime.date(2013, 4, 21)
33+
34+
def test_time():
35+
data = create_insert_select('i time, u time', "'9:6:3', 151413")
36+
assert data[0] == datetime.timedelta(0, 32763)
37+
assert data[1] == datetime.timedelta(0, 54853)
38+
39+
def test_year():
40+
data = create_insert_select('i year, u year', "1990, '2012'")
41+
42+
assert data[0] == 1990
43+
assert data[1] == 2012
44+
45+
def test_datetime():
46+
data = create_insert_select('i datetime, u datetime', "'2011-03-11', '2012-04-19 13:08:22'")
47+
assert data[0] == datetime.datetime(2011, 3, 11, 0, 0)
48+
assert data[1] == datetime.datetime(2012, 4, 19, 13, 8, 22)
49+
50+
def test_timestamp():
51+
data = create_insert_select('i timestamp', "'2012-04-19 13:08:22'")
52+
assert data[0] == datetime.datetime(2012, 4, 19, 13, 8, 22)

tests/test_longtext.py

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import mysql.connector as mariadb
2+
from os import getenv
3+
4+
TABLE = getenv('DB2I_TABLE') or 'test'
5+
DB = getenv('DB2I_DB') or 'db2itest'
6+
HOST = getenv('DB2I_HOST') or '127.0.0.1'
7+
USER = getenv('DB2I_USER') or 'root'
8+
PASS = getenv('DB2I_PASS') or ''
9+
EXPECTED = getenv('DB2I_EXPECTED') or 'Hello World'
10+
11+
def create_insert_select(charset, collation="general_ci", expected=EXPECTED, encoding=None):
12+
collation = f'{charset}_{collation}'
13+
is_unicode = True if 'utf' in charset or 'ucs' in charset else False
14+
use_unicode = True if is_unicode else False
15+
conn_charset = 'utf8' if is_unicode else charset
16+
conn_collation = 'utf8_general_ci' if is_unicode else collation
17+
18+
conn = mariadb.connect(user=USER, password=PASS, host=HOST, database=DB,
19+
charset=conn_charset, collation=conn_collation, use_unicode=use_unicode)
20+
21+
cursor = conn.cursor()
22+
cursor.execute(f"DROP TABLE IF EXISTS {TABLE}")
23+
conn.commit()
24+
cursor.execute(f"CREATE TABLE {TABLE} (i longtext) engine=ibmdb2i CHARACTER SET '{charset}' COLLATE '{collation}'")
25+
cursor.execute(f"INSERT INTO {TABLE} VALUES(%s)", (expected,))
26+
conn.commit()
27+
cursor.execute(f"SELECT i FROM {TABLE}")
28+
data = cursor.fetchone()
29+
if encoding:
30+
data = data[0].decode(encoding)
31+
else:
32+
data = data[0]
33+
34+
print(f'Data is: {data}')
35+
cursor.execute(f"DROP TABLE {TABLE}")
36+
conn.commit()
37+
cursor.close()
38+
conn.close()
39+
return data
40+
41+
def test_utf8():
42+
data = create_insert_select('utf8')
43+
assert data == EXPECTED
44+
45+
def test_utf8mb4():
46+
data = create_insert_select('utf8mb4')
47+
assert data == EXPECTED
48+
49+
def test_utf8mb3():
50+
data = create_insert_select('utf8mb3')
51+
assert data == EXPECTED
52+
53+
def test_utf16():
54+
data = create_insert_select('utf16')
55+
assert data == EXPECTED
56+
57+
def test_ucs2():
58+
data = create_insert_select('ucs2')
59+
assert data == EXPECTED
60+
61+
def test_ascii():
62+
# https://en.wikipedia.org/wiki/ASCII#Character_set
63+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F))]).decode('ascii')
64+
data = create_insert_select('ascii', expected=EXPECTED, encoding='ascii')
65+
assert data == EXPECTED
66+
67+
def test_latin1():
68+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-1#Code_page_layout
69+
# CCSID 1148 does not include ¤ (00A4) because its replaced by €
70+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
71+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-1')
72+
data = create_insert_select('latin1', expected=EXPECTED, encoding='iso8859-1')
73+
assert data == EXPECTED
74+
75+
def test_latin2():
76+
# CCSID 1153 does not include ¤ (00A4) because its replaced by €
77+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-2#Code_page_layout
78+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
79+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-2')
80+
data = create_insert_select('latin2', expected=EXPECTED, encoding='iso8859-2')
81+
assert data == EXPECTED
82+
83+
def test_greek():
84+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-7#Codepage_layout
85+
# CCSID 4971 does not support ₯ drachma sign (0XA5) and ͺ Greek ypogegrammeni (0XAA)
86+
# these are available in CCSID 9067 (March 2005) ?
87+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA5))
88+
+ tuple(range(0XA6, 0XAA)) + tuple(range(0XAB, 0XAE)) + tuple(range(0XAF, 0XD2))
89+
+ tuple(range(0XD4, 0XFF))]).decode('iso8859-7')
90+
data = create_insert_select('greek', expected=EXPECTED, encoding='iso8859-7')
91+
assert data == EXPECTED
92+
93+
def test_hebrew():
94+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-8#Codepage_layout
95+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA1))
96+
+ tuple(range(0XA2, 0XBF)) + tuple(range(0XDF, 0XFB))]).decode('iso8859-8')
97+
data = create_insert_select('hebrew', expected=EXPECTED, encoding='iso8859-8')
98+
assert data == EXPECTED
99+
100+
def test_latin5():
101+
# https://en.wikipedia.org/wiki/ISO/IEC_8859-9#Codepage_layout
102+
# CCSID 1155 does not include ¤ (00A4) because its replaced by €
103+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA0, 0XA4))
104+
+ tuple(range(0XA5, 0X100))]).decode('iso8859-9')
105+
data = create_insert_select('latin5', 'turkish_ci', expected=EXPECTED, encoding='iso8859-9')
106+
assert data == EXPECTED
107+
108+
def test_tis620():
109+
# https://en.wikipedia.org/wiki/Thai_Industrial_Standard_620-2533#Character_set
110+
# The sole difference is that ISO/IEC 8859-11 allocates non-breaking space to code 0xA0,
111+
# while TIS-620 leaves it undefined. (In practice, this small distinction is usually ignored.)
112+
# Here we skip over nbsp 0xA0
113+
EXPECTED = b''.join([bytes([i]) for i in tuple(range(0X20, 0X7F)) + tuple(range(0XA1, 0XDB))
114+
+ tuple(range(0XDF, 0XFC))]).decode('iso8859-11')
115+
data = create_insert_select('tis620', 'thai_ci', expected=EXPECTED, encoding='iso8859-11')
116+
assert data == EXPECTED

0 commit comments

Comments
 (0)