ticket47490_test.py 27 KB

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