ticket47490_test.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. '''
  2. Created on Nov 7, 2013
  3. @author: tbordaz
  4. '''
  5. import os
  6. import sys
  7. import time
  8. import ldap
  9. import logging
  10. import socket
  11. import time
  12. import logging
  13. import pytest
  14. import re
  15. from lib389 import DirSrv, Entry, tools
  16. from lib389.tools import DirSrvTools
  17. from lib389._constants import *
  18. from lib389.properties import *
  19. from constants import *
  20. logging.getLogger(__name__).setLevel(logging.DEBUG)
  21. log = logging.getLogger(__name__)
  22. installation_prefix = None
  23. TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
  24. ENTRY_DN = "cn=test_entry, %s" % SUFFIX
  25. MUST_OLD = "(postalAddress $ preferredLocale)"
  26. MUST_NEW = "(postalAddress $ preferredLocale $ telexNumber)"
  27. MAY_OLD = "(postalCode $ street)"
  28. MAY_NEW = "(postalCode $ street $ postOfficeBox)"
  29. class TopologyMasterConsumer(object):
  30. def __init__(self, master, consumer):
  31. master.open()
  32. self.master = master
  33. consumer.open()
  34. self.consumer = consumer
  35. def _header(topology, label):
  36. topology.master.log.info("\n\n###############################################")
  37. topology.master.log.info("#######")
  38. topology.master.log.info("####### %s" % label)
  39. topology.master.log.info("#######")
  40. topology.master.log.info("###################################################")
  41. def pattern_errorlog(file, log_pattern):
  42. try:
  43. pattern_errorlog.last_pos += 1
  44. except AttributeError:
  45. pattern_errorlog.last_pos = 0
  46. found = None
  47. log.debug("_pattern_errorlog: start at offset %d" % pattern_errorlog.last_pos)
  48. file.seek(pattern_errorlog.last_pos)
  49. # Use a while true iteration because 'for line in file: hit a
  50. # python bug that break file.tell()
  51. while True:
  52. line = file.readline()
  53. log.debug("_pattern_errorlog: [%d] %s" % (file.tell(), line))
  54. found = log_pattern.search(line)
  55. if ((line == '') or (found)):
  56. break
  57. log.debug("_pattern_errorlog: end at offset %d" % file.tell())
  58. pattern_errorlog.last_pos = file.tell()
  59. return found
  60. def _oc_definition(oid_ext, name, must=None, may=None):
  61. oid = "1.2.3.4.5.6.7.8.9.10.%d" % oid_ext
  62. desc = 'To test ticket 47490'
  63. sup = 'person'
  64. if not must:
  65. must = MUST_OLD
  66. if not may:
  67. may = MAY_OLD
  68. new_oc = "( %s NAME '%s' DESC '%s' SUP %s AUXILIARY MUST %s MAY %s )" % (oid, name, desc, sup, must, may)
  69. return new_oc
  70. def add_OC(instance, oid_ext, name):
  71. new_oc = _oc_definition(oid_ext, name)
  72. instance.schema.add_schema('objectClasses', new_oc)
  73. def mod_OC(instance, oid_ext, name, old_must=None, old_may=None, new_must=None, new_may=None):
  74. old_oc = _oc_definition(oid_ext, name, old_must, old_may)
  75. new_oc = _oc_definition(oid_ext, name, new_must, new_may)
  76. instance.schema.del_schema('objectClasses', old_oc)
  77. instance.schema.add_schema('objectClasses', new_oc)
  78. def support_schema_learning(topology):
  79. """
  80. with https://fedorahosted.org/389/ticket/47721, the supplier and consumer can learn
  81. schema definitions when a replication occurs.
  82. Before that ticket: replication of the schema fails requiring administrative operation
  83. In the test the schemaCSN (master consumer) differs
  84. After that ticket: replication of the schema succeeds (after an initial phase of learning)
  85. In the test the schema CSN (master consumer) are in sync
  86. This function returns True if 47721 is fixed in the current release
  87. False else
  88. """
  89. ent = topology.consumer.getEntry(DN_CONFIG, ldap.SCOPE_BASE, "(cn=config)", ['nsslapd-versionstring'])
  90. if ent.hasAttr('nsslapd-versionstring'):
  91. val = ent.getValue('nsslapd-versionstring')
  92. version = val.split('/')[1].split('.') # something like ['1', '3', '1', '23', 'final_fix']
  93. major = int(version[0])
  94. minor = int(version[1])
  95. if major > 1:
  96. return True
  97. if minor > 3:
  98. # version is 1.4 or after
  99. return True
  100. if minor == 3:
  101. if version[2].isdigit():
  102. if int(version[2]) >= 3:
  103. return True
  104. return False
  105. def trigger_update(topology):
  106. """
  107. It triggers an update on the supplier. This will start a replication
  108. session and a schema push
  109. """
  110. try:
  111. trigger_update.value += 1
  112. except AttributeError:
  113. trigger_update.value = 1
  114. replace = [(ldap.MOD_REPLACE, 'telephonenumber', str(trigger_update.value))]
  115. topology.master.modify_s(ENTRY_DN, replace)
  116. # wait 10 seconds that the update is replicated
  117. loop = 0
  118. while loop <= 10:
  119. try:
  120. ent = topology.consumer.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)", ['telephonenumber'])
  121. val = ent.telephonenumber or "0"
  122. if int(val) == trigger_update.value:
  123. return
  124. # the expected value is not yet replicated. try again
  125. time.sleep(1)
  126. loop += 1
  127. log.debug("trigger_update: receive %s (expected %d)" % (val, trigger_update.value))
  128. except ldap.NO_SUCH_OBJECT:
  129. time.sleep(1)
  130. loop += 1
  131. def trigger_schema_push(topology):
  132. '''
  133. Trigger update to create a replication session.
  134. In case of 47721 is fixed and the replica needs to learn the missing definition, then
  135. the first replication session learn the definition and the second replication session
  136. push the schema (and the schemaCSN.
  137. This is why there is two updates and replica agreement is stopped/start (to create a second session)
  138. '''
  139. agreements = topology.master.agreement.list(suffix=SUFFIX, consumer_host=topology.consumer.host, consumer_port=topology.consumer.port)
  140. assert(len(agreements) == 1)
  141. ra = agreements[0]
  142. trigger_update(topology)
  143. topology.master.agreement.pause(ra.dn)
  144. topology.master.agreement.resume(ra.dn)
  145. trigger_update(topology)
  146. @pytest.fixture(scope="module")
  147. def topology(request):
  148. '''
  149. This fixture is used to create a replicated topology for the 'module'.
  150. The replicated topology is MASTER -> Consumer.
  151. At the beginning, It may exists a master instance and/or a consumer instance.
  152. It may also exists a backup for the master and/or the consumer.
  153. Principle:
  154. If master instance exists:
  155. restart it
  156. If consumer instance exists:
  157. restart it
  158. If backup of master AND backup of consumer exists:
  159. create or rebind to consumer
  160. create or rebind to master
  161. restore master from backup
  162. restore consumer from backup
  163. else:
  164. Cleanup everything
  165. remove instances
  166. remove backups
  167. Create instances
  168. Initialize replication
  169. Create backups
  170. '''
  171. global installation_prefix
  172. if installation_prefix:
  173. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  174. master = DirSrv(verbose=False)
  175. consumer = DirSrv(verbose=False)
  176. # Args for the master instance
  177. args_instance[SER_HOST] = HOST_MASTER
  178. args_instance[SER_PORT] = PORT_MASTER
  179. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER
  180. args_master = args_instance.copy()
  181. master.allocate(args_master)
  182. # Args for the consumer instance
  183. args_instance[SER_HOST] = HOST_CONSUMER
  184. args_instance[SER_PORT] = PORT_CONSUMER
  185. args_instance[SER_SERVERID_PROP] = SERVERID_CONSUMER
  186. args_consumer = args_instance.copy()
  187. consumer.allocate(args_consumer)
  188. # Get the status of the backups
  189. backup_master = master.checkBackupFS()
  190. backup_consumer = consumer.checkBackupFS()
  191. # Get the status of the instance and restart it if it exists
  192. instance_master = master.exists()
  193. if instance_master:
  194. master.stop(timeout=10)
  195. master.start(timeout=10)
  196. instance_consumer = consumer.exists()
  197. if instance_consumer:
  198. consumer.stop(timeout=10)
  199. consumer.start(timeout=10)
  200. if backup_master and backup_consumer:
  201. # The backups exist, assuming they are correct
  202. # we just re-init the instances with them
  203. if not instance_master:
  204. master.create()
  205. # Used to retrieve configuration information (dbdir, confdir...)
  206. master.open()
  207. if not instance_consumer:
  208. consumer.create()
  209. # Used to retrieve configuration information (dbdir, confdir...)
  210. consumer.open()
  211. # restore master from backup
  212. master.stop(timeout=10)
  213. master.restoreFS(backup_master)
  214. master.start(timeout=10)
  215. # restore consumer from backup
  216. consumer.stop(timeout=10)
  217. consumer.restoreFS(backup_consumer)
  218. consumer.start(timeout=10)
  219. else:
  220. # We should be here only in two conditions
  221. # - This is the first time a test involve master-consumer
  222. # so we need to create everything
  223. # - Something weird happened (instance/backup destroyed)
  224. # so we discard everything and recreate all
  225. # Remove all the backups. So even if we have a specific backup file
  226. # (e.g backup_master) we clear all backups that an instance my have created
  227. if backup_master:
  228. master.clearBackupFS()
  229. if backup_consumer:
  230. consumer.clearBackupFS()
  231. # Remove all the instances
  232. if instance_master:
  233. master.delete()
  234. if instance_consumer:
  235. consumer.delete()
  236. # Create the instances
  237. master.create()
  238. master.open()
  239. consumer.create()
  240. consumer.open()
  241. #
  242. # Now prepare the Master-Consumer topology
  243. #
  244. # First Enable replication
  245. master.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER)
  246. consumer.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_CONSUMER)
  247. # Initialize the supplier->consumer
  248. properties = {RA_NAME: r'meTo_$host:$port',
  249. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  250. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  251. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  252. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  253. repl_agreement = master.agreement.create(suffix=SUFFIX, host=consumer.host, port=consumer.port, properties=properties)
  254. if not repl_agreement:
  255. log.fatal("Fail to create a replica agreement")
  256. sys.exit(1)
  257. log.debug("%s created" % repl_agreement)
  258. master.agreement.init(SUFFIX, HOST_CONSUMER, PORT_CONSUMER)
  259. master.waitForReplInit(repl_agreement)
  260. # Check replication is working fine
  261. master.add_s(Entry((TEST_REPL_DN, {
  262. 'objectclass': "top person".split(),
  263. 'sn': 'test_repl',
  264. 'cn': 'test_repl'})))
  265. ent = None
  266. loop = 0
  267. while loop <= 10:
  268. try:
  269. ent = consumer.getEntry(TEST_REPL_DN, ldap.SCOPE_BASE, "(objectclass=*)")
  270. break
  271. except ldap.NO_SUCH_OBJECT:
  272. time.sleep(1)
  273. loop += 1
  274. if ent is None:
  275. assert False
  276. # Time to create the backups
  277. master.stop(timeout=10)
  278. master.backupfile = master.backupFS()
  279. master.start(timeout=10)
  280. consumer.stop(timeout=10)
  281. consumer.backupfile = consumer.backupFS()
  282. consumer.start(timeout=10)
  283. # clear the tmp directory
  284. master.clearTmpDir(__file__)
  285. #
  286. # Here we have two instances master and consumer
  287. # with replication working. Either coming from a backup recovery
  288. # or from a fresh (re)init
  289. # Time to return the topology
  290. return TopologyMasterConsumer(master, consumer)
  291. def test_ticket47490_init(topology):
  292. """
  293. Initialize the test environment
  294. """
  295. log.debug("test_ticket47490_init topology %r (master %r, consumer %r" % (topology, topology.master, topology.consumer))
  296. # the test case will check if a warning message is logged in the
  297. # error log of the supplier
  298. topology.master.errorlog_file = open(topology.master.errlog, "r")
  299. # This entry will be used to trigger attempt of schema push
  300. topology.master.add_s(Entry((ENTRY_DN, {
  301. 'objectclass': "top person".split(),
  302. 'sn': 'test_entry',
  303. 'cn': 'test_entry'})))
  304. def test_ticket47490_one(topology):
  305. """
  306. Summary: Extra OC Schema is pushed - no error
  307. If supplier schema is a superset (one extra OC) of consumer schema, then
  308. schema is pushed and there is no message in the error log
  309. State at startup:
  310. - supplier default schema
  311. - consumer default schema
  312. Final state
  313. - supplier +masterNewOCA
  314. - consumer +masterNewOCA
  315. """
  316. _header(topology, "Extra OC Schema is pushed - no error")
  317. log.debug("test_ticket47490_one topology %r (master %r, consumer %r" % (topology, topology.master, topology.consumer))
  318. # update the schema of the supplier so that it is a superset of
  319. # consumer. Schema should be pushed
  320. add_OC(topology.master, 2, 'masterNewOCA')
  321. trigger_schema_push(topology)
  322. master_schema_csn = topology.master.schema.get_schema_csn()
  323. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  324. # Check the schemaCSN was updated on the consumer
  325. log.debug("test_ticket47490_one master_schema_csn=%s", master_schema_csn)
  326. log.debug("ctest_ticket47490_one onsumer_schema_csn=%s", consumer_schema_csn)
  327. assert master_schema_csn == consumer_schema_csn
  328. # Check the error log of the supplier does not contain an error
  329. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  330. res = pattern_errorlog(topology.master.errorlog_file, regex)
  331. if res is not None:
  332. assert False
  333. def test_ticket47490_two(topology):
  334. """
  335. Summary: Extra OC Schema is pushed - (ticket 47721 allows to learn missing def)
  336. If consumer schema is a superset (one extra OC) of supplier schema, then
  337. schema is pushed and there is a message in the error log
  338. State at startup
  339. - supplier +masterNewOCA
  340. - consumer +masterNewOCA
  341. Final state
  342. - supplier +masterNewOCA +masterNewOCB
  343. - consumer +masterNewOCA +consumerNewOCA
  344. """
  345. _header(topology, "Extra OC Schema is pushed - (ticket 47721 allows to learn missing def)")
  346. # add this OC on consumer. Supplier will no push the schema
  347. add_OC(topology.consumer, 1, 'consumerNewOCA')
  348. # add a new OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
  349. time.sleep(2)
  350. add_OC(topology.master, 3, 'masterNewOCB')
  351. # now push the scheam
  352. trigger_schema_push(topology)
  353. master_schema_csn = topology.master.schema.get_schema_csn()
  354. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  355. # Check the schemaCSN was NOT updated on the consumer
  356. # with 47721, supplier learns the missing definition
  357. log.debug("test_ticket47490_two master_schema_csn=%s", master_schema_csn)
  358. log.debug("test_ticket47490_two consumer_schema_csn=%s", consumer_schema_csn)
  359. if support_schema_learning(topology):
  360. assert master_schema_csn == consumer_schema_csn
  361. else:
  362. assert master_schema_csn != consumer_schema_csn
  363. # Check the error log of the supplier does not contain an error
  364. # This message may happen during the learning phase
  365. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  366. res = pattern_errorlog(topology.master.errorlog_file, regex)
  367. def test_ticket47490_three(topology):
  368. """
  369. Summary: Extra OC Schema is pushed - no error
  370. If supplier schema is again a superset (one extra OC), then
  371. schema is pushed and there is no message in the error log
  372. State at startup
  373. - supplier +masterNewOCA +masterNewOCB
  374. - consumer +masterNewOCA +consumerNewOCA
  375. Final state
  376. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
  377. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  378. """
  379. _header(topology, "Extra OC Schema is pushed - no error")
  380. # Do an upate to trigger the schema push attempt
  381. # add this OC on consumer. Supplier will no push the schema
  382. add_OC(topology.master, 1, 'consumerNewOCA')
  383. # now push the scheam
  384. trigger_schema_push(topology)
  385. master_schema_csn = topology.master.schema.get_schema_csn()
  386. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  387. # Check the schemaCSN was NOT updated on the consumer
  388. log.debug("test_ticket47490_three master_schema_csn=%s", master_schema_csn)
  389. log.debug("test_ticket47490_three consumer_schema_csn=%s", consumer_schema_csn)
  390. assert master_schema_csn == consumer_schema_csn
  391. # Check the error log of the supplier does not contain an error
  392. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  393. res = pattern_errorlog(topology.master.errorlog_file, regex)
  394. if res is not None:
  395. assert False
  396. def test_ticket47490_four(topology):
  397. """
  398. Summary: Same OC - extra MUST: Schema is pushed - no error
  399. If supplier schema is again a superset (OC with more MUST), then
  400. schema is pushed and there is no message in the error log
  401. State at startup
  402. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
  403. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  404. Final state
  405. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
  406. +must=telexnumber
  407. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  408. +must=telexnumber
  409. """
  410. _header(topology, "Same OC - extra MUST: Schema is pushed - no error")
  411. mod_OC(topology.master, 2, 'masterNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
  412. trigger_schema_push(topology)
  413. master_schema_csn = topology.master.schema.get_schema_csn()
  414. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  415. # Check the schemaCSN was updated on the consumer
  416. log.debug("test_ticket47490_four master_schema_csn=%s", master_schema_csn)
  417. log.debug("ctest_ticket47490_four onsumer_schema_csn=%s", consumer_schema_csn)
  418. assert master_schema_csn == consumer_schema_csn
  419. # Check the error log of the supplier does not contain an error
  420. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  421. res = pattern_errorlog(topology.master.errorlog_file, regex)
  422. if res is not None:
  423. assert False
  424. def test_ticket47490_five(topology):
  425. """
  426. Summary: Same OC - extra MUST: Schema is pushed - (fix for 47721)
  427. If consumer schema is a superset (OC with more MUST), then
  428. schema is pushed (fix for 47721) and there is a message in the error log
  429. State at startup
  430. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA
  431. +must=telexnumber
  432. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  433. +must=telexnumber
  434. Final state
  435. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  436. +must=telexnumber
  437. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  438. +must=telexnumber +must=telexnumber
  439. Note: replication log is enabled to get more details
  440. """
  441. _header(topology, "Same OC - extra MUST: Schema is pushed - (fix for 47721)")
  442. # get more detail why it fails
  443. topology.master.enableReplLogging()
  444. # add telenumber to 'consumerNewOCA' on the consumer
  445. mod_OC(topology.consumer, 1, 'consumerNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
  446. # add a new OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
  447. time.sleep(2)
  448. add_OC(topology.master, 4, 'masterNewOCC')
  449. trigger_schema_push(topology)
  450. master_schema_csn = topology.master.schema.get_schema_csn()
  451. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  452. # Check the schemaCSN was NOT updated on the consumer
  453. # with 47721, supplier learns the missing definition
  454. log.debug("test_ticket47490_five master_schema_csn=%s", master_schema_csn)
  455. log.debug("ctest_ticket47490_five onsumer_schema_csn=%s", consumer_schema_csn)
  456. if support_schema_learning(topology):
  457. assert master_schema_csn == consumer_schema_csn
  458. else:
  459. assert master_schema_csn != consumer_schema_csn
  460. # Check the error log of the supplier does not contain an error
  461. # This message may happen during the learning phase
  462. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  463. res = pattern_errorlog(topology.master.errorlog_file, regex)
  464. def test_ticket47490_six(topology):
  465. """
  466. Summary: Same OC - extra MUST: Schema is pushed - no error
  467. If supplier schema is again a superset (OC with more MUST), then
  468. schema is pushed and there is no message in the error log
  469. State at startup
  470. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  471. +must=telexnumber
  472. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA
  473. +must=telexnumber +must=telexnumber
  474. Final state
  475. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  476. +must=telexnumber +must=telexnumber
  477. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  478. +must=telexnumber +must=telexnumber
  479. Note: replication log is enabled to get more details
  480. """
  481. _header(topology, "Same OC - extra MUST: Schema is pushed - no error")
  482. # add telenumber to 'consumerNewOCA' on the consumer
  483. mod_OC(topology.master, 1, 'consumerNewOCA', old_must=MUST_OLD, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_OLD)
  484. trigger_schema_push(topology)
  485. master_schema_csn = topology.master.schema.get_schema_csn()
  486. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  487. # Check the schemaCSN was NOT updated on the consumer
  488. log.debug("test_ticket47490_six master_schema_csn=%s", master_schema_csn)
  489. log.debug("ctest_ticket47490_six onsumer_schema_csn=%s", consumer_schema_csn)
  490. assert master_schema_csn == consumer_schema_csn
  491. # Check the error log of the supplier does not contain an error
  492. # This message may happen during the learning phase
  493. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  494. res = pattern_errorlog(topology.master.errorlog_file, regex)
  495. if res is not None:
  496. assert False
  497. def test_ticket47490_seven(topology):
  498. """
  499. Summary: Same OC - extra MAY: Schema is pushed - no error
  500. If supplier schema is again a superset (OC with more MAY), then
  501. schema is pushed and there is no message in the error log
  502. State at startup
  503. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  504. +must=telexnumber +must=telexnumber
  505. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  506. +must=telexnumber +must=telexnumber
  507. Final stat
  508. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  509. +must=telexnumber +must=telexnumber
  510. +may=postOfficeBox
  511. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  512. +must=telexnumber +must=telexnumber
  513. +may=postOfficeBox
  514. """
  515. _header(topology, "Same OC - extra MAY: Schema is pushed - no error")
  516. mod_OC(topology.master, 2, 'masterNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
  517. trigger_schema_push(topology)
  518. master_schema_csn = topology.master.schema.get_schema_csn()
  519. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  520. # Check the schemaCSN was updated on the consumer
  521. log.debug("test_ticket47490_seven master_schema_csn=%s", master_schema_csn)
  522. log.debug("ctest_ticket47490_seven consumer_schema_csn=%s", consumer_schema_csn)
  523. assert master_schema_csn == consumer_schema_csn
  524. # Check the error log of the supplier does not contain an error
  525. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  526. res = pattern_errorlog(topology.master.errorlog_file, regex)
  527. if res is not None:
  528. assert False
  529. def test_ticket47490_eight(topology):
  530. """
  531. Summary: Same OC - extra MAY: Schema is pushed (fix for 47721)
  532. If consumer schema is a superset (OC with more MAY), then
  533. schema is pushed (fix for 47721) and there is message in the error log
  534. State at startup
  535. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  536. +must=telexnumber +must=telexnumber
  537. +may=postOfficeBox
  538. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  539. +must=telexnumber +must=telexnumber
  540. +may=postOfficeBox
  541. Final state
  542. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  543. +must=telexnumber +must=telexnumber
  544. +may=postOfficeBox +may=postOfficeBox
  545. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  546. +must=telexnumber +must=telexnumber
  547. +may=postOfficeBox +may=postOfficeBox
  548. """
  549. _header(topology, "Same OC - extra MAY: Schema is pushed (fix for 47721)")
  550. mod_OC(topology.consumer, 1, 'consumerNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
  551. # modify OC on the supplier so that its nsSchemaCSN is larger than the consumer (wait 2s)
  552. time.sleep(2)
  553. mod_OC(topology.master, 4, 'masterNewOCC', old_must=MUST_OLD, new_must=MUST_OLD, old_may=MAY_OLD, new_may=MAY_NEW)
  554. trigger_schema_push(topology)
  555. master_schema_csn = topology.master.schema.get_schema_csn()
  556. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  557. # Check the schemaCSN was not updated on the consumer
  558. # with 47721, supplier learns the missing definition
  559. log.debug("test_ticket47490_eight master_schema_csn=%s", master_schema_csn)
  560. log.debug("ctest_ticket47490_eight onsumer_schema_csn=%s", consumer_schema_csn)
  561. if support_schema_learning(topology):
  562. assert master_schema_csn == consumer_schema_csn
  563. else:
  564. assert master_schema_csn != consumer_schema_csn
  565. # Check the error log of the supplier does not contain an error
  566. # This message may happen during the learning phase
  567. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  568. res = pattern_errorlog(topology.master.errorlog_file, regex)
  569. def test_ticket47490_nine(topology):
  570. """
  571. Summary: Same OC - extra MAY: Schema is pushed - no error
  572. If consumer schema is a superset (OC with more MAY), then
  573. schema is not pushed and there is message in the error log
  574. State at startup
  575. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  576. +must=telexnumber +must=telexnumber
  577. +may=postOfficeBox +may=postOfficeBox
  578. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  579. +must=telexnumber +must=telexnumber
  580. +may=postOfficeBox +may=postOfficeBox
  581. Final state
  582. - supplier +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  583. +must=telexnumber +must=telexnumber
  584. +may=postOfficeBox +may=postOfficeBox +may=postOfficeBox
  585. - consumer +masterNewOCA +masterNewOCB +consumerNewOCA +masterNewOCC
  586. +must=telexnumber +must=telexnumber
  587. +may=postOfficeBox +may=postOfficeBox +may=postOfficeBox
  588. """
  589. _header(topology, "Same OC - extra MAY: Schema is pushed - no error")
  590. mod_OC(topology.master, 1, 'consumerNewOCA', old_must=MUST_NEW, new_must=MUST_NEW, old_may=MAY_OLD, new_may=MAY_NEW)
  591. trigger_schema_push(topology)
  592. master_schema_csn = topology.master.schema.get_schema_csn()
  593. consumer_schema_csn = topology.consumer.schema.get_schema_csn()
  594. # Check the schemaCSN was updated on the consumer
  595. log.debug("test_ticket47490_nine master_schema_csn=%s", master_schema_csn)
  596. log.debug("ctest_ticket47490_nine onsumer_schema_csn=%s", consumer_schema_csn)
  597. assert master_schema_csn == consumer_schema_csn
  598. # Check the error log of the supplier does not contain an error
  599. regex = re.compile("must not be overwritten \(set replication log for additional info\)")
  600. res = pattern_errorlog(topology.master.errorlog_file, regex)
  601. if res is not None:
  602. assert False
  603. def test_ticket47490_final(topology):
  604. topology.master.delete()
  605. topology.consumer.delete()
  606. def run_isolated():
  607. '''
  608. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  609. To run isolated without py.test, you need to
  610. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  611. - set the installation prefix
  612. - run this program
  613. '''
  614. global installation_prefix
  615. installation_prefix = None
  616. topo = topology(True)
  617. test_ticket47490_init(topo)
  618. test_ticket47490_one(topo)
  619. test_ticket47490_two(topo)
  620. test_ticket47490_three(topo)
  621. test_ticket47490_four(topo)
  622. test_ticket47490_five(topo)
  623. test_ticket47490_six(topo)
  624. test_ticket47490_seven(topo)
  625. test_ticket47490_eight(topo)
  626. test_ticket47490_nine(topo)
  627. test_ticket47490_final(topo)
  628. if __name__ == '__main__':
  629. run_isolated()