comparison test_capabilities.py @ 0:e48810735f11 MySQLdb

Copying 1.2.1 to be the new trunk
author adustman
date Sun, 02 Apr 2006 18:20:53 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e48810735f11
1 #!/usr/bin/env python -O
2 """ Script to test database capabilities and the DB-API interface
3 for functionality and memory leaks.
4
5 Adapted from a script by M-A Lemburg.
6
7 """
8 from time import time
9 import array
10 import unittest
11
12
13 class DatabaseTest(unittest.TestCase):
14
15 db_module = None
16 connect_args = ()
17 connect_kwargs = dict()
18 create_table_extra = ''
19 rows = 10
20 debug = False
21
22 def setUp(self):
23 import gc
24 db = self.db_module.connect(*self.connect_args, **self.connect_kwargs)
25 self.connection = db
26 self.cursor = db.cursor()
27 self.BLOBText = ''.join([chr(i) for i in range(256)] * 100);
28 self.BLOBUText = u''.join([unichr(i) for i in range(16384)])
29 self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16))
30
31 leak_test = True
32
33 def tearDown(self):
34 if self.leak_test:
35 import gc
36 del self.cursor
37 orphans = gc.collect()
38 self.failIf(orphans, "%d orphaned objects found after deleting cursor" % orphans)
39
40 del self.connection
41 orphans = gc.collect()
42 self.failIf(orphans, "%d orphaned objects found after deleting connection" % orphans)
43
44 def table_exists(self, name):
45 try:
46 self.cursor.execute('select * from %s where 1=0' % name)
47 except:
48 return False
49 else:
50 return True
51
52 def quote_identifier(self, ident):
53 return '"%s"' % ident
54
55 def new_table_name(self):
56 i = id(self.cursor)
57 while True:
58 name = self.quote_identifier('tb%08x' % i)
59 if not self.table_exists(name):
60 return name
61 i = i + 1
62
63 def create_table(self, columndefs):
64
65 """ Create a table using a list of column definitions given in
66 columndefs.
67
68 generator must be a function taking arguments (row_number,
69 col_number) returning a suitable data object for insertion
70 into the table.
71
72 """
73 self.table = self.new_table_name()
74 self.cursor.execute('CREATE TABLE %s (%s) %s' %
75 (self.table,
76 ',\n'.join(columndefs),
77 self.create_table_extra))
78
79 def check_data_integrity(self, columndefs, generator):
80 # insert
81 self.create_table(columndefs)
82 insert_statement = ('INSERT INTO %s VALUES (%s)' %
83 (self.table,
84 ','.join(['%s'] * len(columndefs))))
85 data = [ [ generator(i,j) for j in range(len(columndefs)) ]
86 for i in range(self.rows) ]
87 if self.debug:
88 print data
89 self.cursor.executemany(insert_statement, data)
90 self.connection.commit()
91 # verify
92 self.cursor.execute('select * from %s' % self.table)
93 l = self.cursor.fetchall()
94 if self.debug:
95 print l
96 self.assertEquals(len(l), self.rows)
97 try:
98 for i in range(self.rows):
99 for j in range(len(columndefs)):
100 self.assertEquals(l[i][j], generator(i,j))
101 finally:
102 if not self.debug:
103 self.cursor.execute('drop table %s' % (self.table))
104
105 def test_transactions(self):
106 columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
107 def generator(row, col):
108 if col == 0: return row
109 else: return ('%i' % (row%10))*255
110 self.create_table(columndefs)
111 insert_statement = ('INSERT INTO %s VALUES (%s)' %
112 (self.table,
113 ','.join(['%s'] * len(columndefs))))
114 data = [ [ generator(i,j) for j in range(len(columndefs)) ]
115 for i in range(self.rows) ]
116 self.cursor.executemany(insert_statement, data)
117 # verify
118 self.connection.commit()
119 self.cursor.execute('select * from %s' % self.table)
120 l = self.cursor.fetchall()
121 self.assertEquals(len(l), self.rows)
122 for i in range(self.rows):
123 for j in range(len(columndefs)):
124 self.assertEquals(l[i][j], generator(i,j))
125 delete_statement = 'delete from %s where col1=%%s' % self.table
126 self.cursor.execute(delete_statement, (0,))
127 self.cursor.execute('select col1 from %s where col1=%s' % \
128 (self.table, 0))
129 l = self.cursor.fetchall()
130 self.failIf(l, "DELETE didn't work")
131 self.connection.rollback()
132 self.cursor.execute('select col1 from %s where col1=%s' % \
133 (self.table, 0))
134 l = self.cursor.fetchall()
135 self.failUnless(len(l) == 1, "ROLLBACK didn't work")
136 self.cursor.execute('drop table %s' % (self.table))
137
138 def test_truncation(self):
139 columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
140 def generator(row, col):
141 if col == 0: return row
142 else: return ('%i' % (row%10))*((255-self.rows/2)+row)
143 self.create_table(columndefs)
144 insert_statement = ('INSERT INTO %s VALUES (%s)' %
145 (self.table,
146 ','.join(['%s'] * len(columndefs))))
147
148 try:
149 self.cursor.execute(insert_statement, (0, '0'*256))
150 except Warning:
151 if self.debug: print self.cursor.messages
152 except self.connection.DataError:
153 pass
154 else:
155 self.fail("Over-long column did not generate warnings/exception with single insert")
156
157 self.connection.rollback()
158
159 try:
160 for i in range(self.rows):
161 data = []
162 for j in range(len(columndefs)):
163 data.append(generator(i,j))
164 self.cursor.execute(insert_statement,tuple(data))
165 except Warning:
166 if self.debug: print self.cursor.messages
167 except self.connection.DataError:
168 pass
169 else:
170 self.fail("Over-long columns did not generate warnings/exception with execute()")
171
172 self.connection.rollback()
173
174 try:
175 data = [ [ generator(i,j) for j in range(len(columndefs)) ]
176 for i in range(self.rows) ]
177 self.cursor.executemany(insert_statement, data)
178 except Warning:
179 if self.debug: print self.cursor.messages
180 except self.connection.DataError:
181 pass
182 else:
183 self.fail("Over-long columns did not generate warnings/exception with executemany()")
184
185 self.connection.rollback()
186 self.cursor.execute('drop table %s' % (self.table))
187
188 def test_CHAR(self):
189 # Character data
190 def generator(row,col):
191 return ('%i' % ((row+col) % 10)) * 255
192 self.check_data_integrity(
193 ('col1 char(255)','col2 char(255)'),
194 generator)
195
196 def test_INT(self):
197 # Number data
198 def generator(row,col):
199 return row*row
200 self.check_data_integrity(
201 ('col1 INT',),
202 generator)
203
204 def test_DECIMAL(self):
205 # DECIMAL
206 def generator(row,col):
207 from decimal import Decimal
208 return Decimal("%d.%02d" % (row, col))
209 self.check_data_integrity(
210 ('col1 DECIMAL(5,2)',),
211 generator)
212
213 def test_DATE(self):
214 ticks = time()
215 def generator(row,col):
216 return self.db_module.DateFromTicks(ticks+row*86400-col*1313)
217 self.check_data_integrity(
218 ('col1 DATE',),
219 generator)
220
221 def test_TIME(self):
222 ticks = time()
223 def generator(row,col):
224 return self.db_module.TimeFromTicks(ticks+row*86400-col*1313)
225 self.check_data_integrity(
226 ('col1 TIME',),
227 generator)
228
229 def test_DATETIME(self):
230 ticks = time()
231 def generator(row,col):
232 return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
233 self.check_data_integrity(
234 ('col1 DATETIME',),
235 generator)
236
237 def test_TIMESTAMP(self):
238 ticks = time()
239 def generator(row,col):
240 return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
241 self.check_data_integrity(
242 ('col1 TIMESTAMP',),
243 generator)
244
245 def test_fractional_TIMESTAMP(self):
246 ticks = time()
247 def generator(row,col):
248 return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313+row*0.7*col/3.0)
249 self.check_data_integrity(
250 ('col1 TIMESTAMP',),
251 generator)
252
253 def test_LONG(self):
254 def generator(row,col):
255 if col == 0:
256 return row
257 else:
258 return self.BLOBUText # 'BLOB Text ' * 1024
259 self.check_data_integrity(
260 ('col1 INT','col2 LONG'),
261 generator)
262
263 def test_TEXT(self):
264 def generator(row,col):
265 return self.BLOBUText # 'BLOB Text ' * 1024
266 self.check_data_integrity(
267 ('col2 TEXT',),
268 generator)
269
270 def test_LONG_BYTE(self):
271 def generator(row,col):
272 if col == 0:
273 return row
274 else:
275 return self.BLOBBinary # 'BLOB\000Binary ' * 1024
276 self.check_data_integrity(
277 ('col1 INT','col2 LONG BYTE'),
278 generator)
279
280 def test_BLOB(self):
281 def generator(row,col):
282 if col == 0:
283 return row
284 else:
285 return self.BLOBBinary # 'BLOB\000Binary ' * 1024
286 self.check_data_integrity(
287 ('col1 INT','col2 BLOB'),
288 generator)
289