| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 """ | |
| 5 Tests for twisted.enterprise reflectors. | |
| 6 """ | |
| 7 | |
| 8 import random | |
| 9 | |
| 10 from twisted.internet import reactor, interfaces, defer | |
| 11 from twisted.enterprise.row import RowObject | |
| 12 from twisted.enterprise.reflector import EQUAL | |
| 13 from twisted.enterprise.sqlreflector import SQLReflector | |
| 14 from twisted.enterprise import util | |
| 15 from twisted.test.test_adbapi import makeSQLTests | |
| 16 from twisted.trial.util import suppress as suppressWarning | |
| 17 from twisted.trial import unittest | |
| 18 | |
| 19 | |
| 20 tableName = "testTable" | |
| 21 childTableName = "childTable" | |
| 22 | |
| 23 | |
| 24 class TestRow(RowObject): | |
| 25 rowColumns = [("key_string", "varchar"), | |
| 26 ("col2", "int"), | |
| 27 ("another_column", "varchar"), | |
| 28 ("Column4", "varchar"), | |
| 29 ("column_5_", "int")] | |
| 30 rowKeyColumns = [("key_string", "varchar")] | |
| 31 rowTableName = tableName | |
| 32 | |
| 33 | |
| 34 class ChildRow(RowObject): | |
| 35 rowColumns = [("childId", "int"), | |
| 36 ("foo", "varchar"), | |
| 37 ("test_key", "varchar"), | |
| 38 ("stuff", "varchar"), | |
| 39 ("gogogo", "int"), | |
| 40 ("data", "varchar")] | |
| 41 rowKeyColumns = [("childId", "int")] | |
| 42 rowTableName = childTableName | |
| 43 rowForeignKeys = [(tableName, | |
| 44 [("test_key","varchar")], | |
| 45 [("key_string","varchar")], | |
| 46 None, 1)] | |
| 47 | |
| 48 | |
| 49 main_table_schema = """ | |
| 50 CREATE TABLE testTable ( | |
| 51 key_string varchar(64), | |
| 52 col2 integer, | |
| 53 another_column varchar(64), | |
| 54 Column4 varchar(64), | |
| 55 column_5_ integer | |
| 56 ) | |
| 57 """ | |
| 58 | |
| 59 child_table_schema = """ | |
| 60 CREATE TABLE childTable ( | |
| 61 childId integer, | |
| 62 foo varchar(64), | |
| 63 test_key varchar(64), | |
| 64 stuff varchar(64), | |
| 65 gogogo integer, | |
| 66 data varchar(64) | |
| 67 ) | |
| 68 """ | |
| 69 | |
| 70 | |
| 71 def randomizeRow(row, nulls_ok=True, trailing_spaces_ok=True): | |
| 72 values = {} | |
| 73 for name, type in row.rowColumns: | |
| 74 if util.getKeyColumn(row, name): | |
| 75 values[name] = getattr(row, name) | |
| 76 continue | |
| 77 elif nulls_ok and random.randint(0, 9) == 0: | |
| 78 value = None # null | |
| 79 elif type == 'int': | |
| 80 value = random.randint(-10000, 10000) | |
| 81 else: | |
| 82 if random.randint(0, 9) == 0: | |
| 83 value = '' | |
| 84 else: | |
| 85 value = ''.join(map(lambda i:chr(random.randrange(32,127)), | |
| 86 xrange(random.randint(1, 64)))) | |
| 87 if not trailing_spaces_ok: | |
| 88 value = value.rstrip() | |
| 89 setattr(row, name, value) | |
| 90 values[name] = value | |
| 91 return values | |
| 92 | |
| 93 | |
| 94 def rowMatches(row, values): | |
| 95 for name, type in row.rowColumns: | |
| 96 if getattr(row, name) != values[name]: | |
| 97 print ("Mismatch on column %s: |%s| (row) |%s| (values)" % | |
| 98 (name, getattr(row, name), values[name])) | |
| 99 return False | |
| 100 return True | |
| 101 | |
| 102 | |
| 103 rowObjectSuppression = suppressWarning( | |
| 104 message="twisted.enterprise.row is deprecated since Twisted 8.0", | |
| 105 category=DeprecationWarning) | |
| 106 | |
| 107 | |
| 108 reflectorSuppression = suppressWarning( | |
| 109 message="twisted.enterprise.reflector is deprecated since Twisted 8.0", | |
| 110 category=DeprecationWarning) | |
| 111 | |
| 112 | |
| 113 class ReflectorTestBase: | |
| 114 """ | |
| 115 Base class for testing reflectors. | |
| 116 """ | |
| 117 | |
| 118 if interfaces.IReactorThreads(reactor, None) is None: | |
| 119 skip = "No thread support, no reflector tests" | |
| 120 | |
| 121 count = 100 # a parameter used for running iterative tests | |
| 122 | |
| 123 def randomizeRow(self, row): | |
| 124 return randomizeRow(row, self.nulls_ok, self.trailing_spaces_ok) | |
| 125 | |
| 126 def setUp(self): | |
| 127 d = self.createReflector() | |
| 128 d.addCallback(self._cbSetUp) | |
| 129 return d | |
| 130 | |
| 131 def _cbSetUp(self, reflector): | |
| 132 self.reflector = reflector | |
| 133 | |
| 134 def tearDown(self): | |
| 135 return self.destroyReflector() | |
| 136 | |
| 137 def destroyReflector(self): | |
| 138 pass | |
| 139 | |
| 140 def test_reflector(self): | |
| 141 """ | |
| 142 Full featured tests of reflector. | |
| 143 """ | |
| 144 # create one row to work with | |
| 145 row = TestRow() | |
| 146 row.assignKeyAttr("key_string", "first") | |
| 147 values = self.randomizeRow(row) | |
| 148 | |
| 149 # save it | |
| 150 d = self.reflector.insertRow(row) | |
| 151 | |
| 152 def _loadBack(_): | |
| 153 # now load it back in | |
| 154 whereClause = [("key_string", EQUAL, "first")] | |
| 155 d = self.reflector.loadObjectsFrom(tableName, | |
| 156 whereClause=whereClause) | |
| 157 return d.addCallback(self.gotData) | |
| 158 | |
| 159 def _getParent(_): | |
| 160 # make sure it came back as what we saved | |
| 161 self.failUnless(len(self.data) == 1, "no row") | |
| 162 parent = self.data[0] | |
| 163 self.failUnless(rowMatches(parent, values), "no match") | |
| 164 return parent | |
| 165 | |
| 166 d.addCallback(_loadBack) | |
| 167 d.addCallback(_getParent) | |
| 168 d.addCallback(self._cbTestReflector) | |
| 169 return d | |
| 170 test_reflector.suppress = [rowObjectSuppression, reflectorSuppression] | |
| 171 | |
| 172 def _cbTestReflector(self, parent): | |
| 173 # create some child rows | |
| 174 test_values = {} | |
| 175 inserts = [] | |
| 176 child_values = {} | |
| 177 for i in range(0, self.num_iterations): | |
| 178 row = ChildRow() | |
| 179 row.assignKeyAttr("childId", i) | |
| 180 values = self.randomizeRow(row) | |
| 181 values['test_key'] = row.test_key = "first" | |
| 182 child_values[i] = values | |
| 183 inserts.append(self.reflector.insertRow(row)) | |
| 184 row = None | |
| 185 #del inserts | |
| 186 d = defer.gatherResults(inserts) | |
| 187 values = [None] | |
| 188 | |
| 189 def _loadObjects(_): | |
| 190 d = self.reflector.loadObjectsFrom(childTableName, parentRow=parent) | |
| 191 return d.addCallback(self.gotData) | |
| 192 | |
| 193 def _checkLoadObjects(_): | |
| 194 self.failUnless(len(self.data) == self.num_iterations, | |
| 195 "no rows on query") | |
| 196 self.failUnless(len(parent.childRows) == self.num_iterations, | |
| 197 "did not load child rows: %d" % len(parent.childRows
)) | |
| 198 for child in parent.childRows: | |
| 199 self.failUnless(rowMatches(child, child_values[child.childId]), | |
| 200 "child %d does not match" % child.childId) | |
| 201 | |
| 202 def _checkLoadObjects2(_): | |
| 203 self.failUnless(len(self.data) == self.num_iterations, | |
| 204 "no rows on query") | |
| 205 self.failUnless(len(parent.childRows) == self.num_iterations, | |
| 206 "child rows added twice!: %d" % len(parent.childRows
)) | |
| 207 | |
| 208 def _changeParent(_): | |
| 209 # now change the parent | |
| 210 values[0] = self.randomizeRow(parent) | |
| 211 return self.reflector.updateRow(parent) | |
| 212 | |
| 213 def _loadBack(_): | |
| 214 # now load it back in | |
| 215 whereClause = [("key_string", EQUAL, "first")] | |
| 216 d = self.reflector.loadObjectsFrom(tableName, whereClause=whereClaus
e) | |
| 217 return d.addCallback(self.gotData) | |
| 218 | |
| 219 def _checkLoadBack(_): | |
| 220 # make sure it came back as what we saved | |
| 221 self.failUnless(len(self.data) == 1, "no row") | |
| 222 parent = self.data[0] | |
| 223 self.failUnless(rowMatches(parent, values[0]), "no match") | |
| 224 # save parent | |
| 225 test_values[parent.key_string] = values[0] | |
| 226 parent = None | |
| 227 | |
| 228 def _saveMoreTestRows(_): | |
| 229 # save some more test rows | |
| 230 ds = [] | |
| 231 for i in range(0, self.num_iterations): | |
| 232 row = TestRow() | |
| 233 row.assignKeyAttr("key_string", "bulk%d"%i) | |
| 234 test_values[row.key_string] = self.randomizeRow(row) | |
| 235 ds.append(self.reflector.insertRow(row)) | |
| 236 return defer.gatherResults(ds) | |
| 237 | |
| 238 def _loadRowsBack(_): | |
| 239 # now load them all back in | |
| 240 d = self.reflector.loadObjectsFrom("testTable") | |
| 241 return d.addCallback(self.gotData) | |
| 242 | |
| 243 def _checkRowsBack(_): | |
| 244 # make sure they are the same | |
| 245 self.failUnless(len(self.data) == self.num_iterations + 1, | |
| 246 "query did not get rows") | |
| 247 for row in self.data: | |
| 248 self.failUnless(rowMatches(row, test_values[row.key_string]), | |
| 249 "child %s does not match" % row.key_string) | |
| 250 | |
| 251 def _changeRows(_): | |
| 252 # now change them all | |
| 253 ds = [] | |
| 254 for row in self.data: | |
| 255 test_values[row.key_string] = self.randomizeRow(row) | |
| 256 ds.append(self.reflector.updateRow(row)) | |
| 257 d = defer.gatherResults(ds) | |
| 258 return d.addCallback(_cbChangeRows) | |
| 259 | |
| 260 def _cbChangeRows(_): | |
| 261 self.data = None | |
| 262 | |
| 263 def _deleteRows(_): | |
| 264 # now delete them | |
| 265 ds = [] | |
| 266 for row in self.data: | |
| 267 ds.append(self.reflector.deleteRow(row)) | |
| 268 d = defer.gatherResults(ds) | |
| 269 return d.addCallback(_cbChangeRows) | |
| 270 | |
| 271 def _checkRowsDeleted(_): | |
| 272 self.failUnless(len(self.data) == 0, "rows were not deleted") | |
| 273 | |
| 274 d.addCallback(_loadObjects) | |
| 275 d.addCallback(_checkLoadObjects) | |
| 276 d.addCallback(_loadObjects) | |
| 277 d.addCallback(_checkLoadObjects2) | |
| 278 d.addCallback(_changeParent) | |
| 279 d.addCallback(_loadBack) | |
| 280 d.addCallback(_checkLoadBack) | |
| 281 d.addCallback(_saveMoreTestRows) | |
| 282 d.addCallback(_loadRowsBack) | |
| 283 d.addCallback(_checkRowsBack) | |
| 284 d.addCallback(_changeRows) | |
| 285 d.addCallback(_loadRowsBack) | |
| 286 d.addCallback(_checkRowsBack) | |
| 287 d.addCallback(_deleteRows) | |
| 288 d.addCallback(_loadRowsBack) | |
| 289 d.addCallback(_checkRowsDeleted) | |
| 290 return d | |
| 291 | |
| 292 | |
| 293 def test_saveAndDelete(self): | |
| 294 """ | |
| 295 Create a row and then try to delete it. | |
| 296 """ | |
| 297 # create one row to work with | |
| 298 row = TestRow() | |
| 299 row.assignKeyAttr("key_string", "first") | |
| 300 values = self.randomizeRow(row) | |
| 301 # save it | |
| 302 d = self.reflector.insertRow(row) | |
| 303 def _deleteRow(_): | |
| 304 # delete it | |
| 305 return self.reflector.deleteRow(row) | |
| 306 d.addCallback(_deleteRow) | |
| 307 return d | |
| 308 test_saveAndDelete.suppress = [rowObjectSuppression, reflectorSuppression] | |
| 309 | |
| 310 | |
| 311 def gotData(self, data): | |
| 312 self.data = data | |
| 313 | |
| 314 | |
| 315 ReflectorTestBase.timeout = 30.0 | |
| 316 | |
| 317 | |
| 318 class SQLReflectorTestBase(ReflectorTestBase): | |
| 319 """ | |
| 320 Base class for the SQL reflector. | |
| 321 """ | |
| 322 | |
| 323 def createReflector(self): | |
| 324 self.startDB() | |
| 325 self.dbpool = self.makePool() | |
| 326 self.dbpool.start() | |
| 327 | |
| 328 if self.can_clear: | |
| 329 d = self.dbpool.runOperation('DROP TABLE testTable') | |
| 330 d.addCallback(lambda _: | |
| 331 self.dbpool.runOperation('DROP TABLE childTable')) | |
| 332 d.addErrback(lambda _: None) | |
| 333 else: | |
| 334 d = defer.succeed(None) | |
| 335 | |
| 336 d.addCallback(lambda _: self.dbpool.runOperation(main_table_schema)) | |
| 337 d.addCallback(lambda _: self.dbpool.runOperation(child_table_schema)) | |
| 338 reflectorClass = self.escape_slashes and SQLReflector \ | |
| 339 or NoSlashSQLReflector | |
| 340 d.addCallback(lambda _: | |
| 341 reflectorClass(self.dbpool, [TestRow, ChildRow])) | |
| 342 return d | |
| 343 | |
| 344 def destroyReflector(self): | |
| 345 d = self.dbpool.runOperation('DROP TABLE testTable') | |
| 346 d.addCallback(lambda _: | |
| 347 self.dbpool.runOperation('DROP TABLE childTable')) | |
| 348 def close(_): | |
| 349 self.dbpool.close() | |
| 350 self.stopDB() | |
| 351 d.addCallback(close) | |
| 352 return d | |
| 353 | |
| 354 | |
| 355 class DeprecationTestCase(unittest.TestCase): | |
| 356 """ | |
| 357 Test various deprecations of twisted.enterprise. | |
| 358 """ | |
| 359 | |
| 360 def test_rowDeprecation(self): | |
| 361 """ | |
| 362 Test deprecation of L{RowObject}. | |
| 363 """ | |
| 364 def wrapper(): | |
| 365 return TestRow() | |
| 366 self.assertWarns(DeprecationWarning, | |
| 367 "twisted.enterprise.row is deprecated since Twisted 8.0", | |
| 368 __file__, | |
| 369 wrapper) | |
| 370 | |
| 371 def test_reflectorDeprecation(self): | |
| 372 """ | |
| 373 Test deprecation of L{SQLReflector}. | |
| 374 """ | |
| 375 def wrapper(): | |
| 376 return SQLReflector(None, ()) | |
| 377 from twisted.enterprise import sqlreflector | |
| 378 self.assertWarns(DeprecationWarning, | |
| 379 "twisted.enterprise.reflector is deprecated since Twisted 8.0", | |
| 380 sqlreflector.__file__, | |
| 381 wrapper) | |
| 382 | |
| 383 | |
| 384 # GadflyReflectorTestCase SQLiteReflectorTestCase PyPgSQLReflectorTestCase | |
| 385 # PsycopgReflectorTestCase MySQLReflectorTestCase FirebirdReflectorTestCase | |
| 386 makeSQLTests(SQLReflectorTestBase, 'ReflectorTestCase', globals()) | |
| 387 | |
| 388 | |
| 389 class NoSlashSQLReflector(SQLReflector): | |
| 390 """ | |
| 391 An sql reflector that only escapes single quotes. | |
| 392 """ | |
| 393 | |
| 394 def escape_string(self, text): | |
| 395 return text.replace("'", "''") | |
| 396 | |
| OLD | NEW |