ticket47823_test.py 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import socket
  7. import pytest
  8. import re
  9. import shutil
  10. from lib389 import DirSrv, Entry, tools
  11. from lib389.tools import DirSrvTools
  12. from lib389._constants import *
  13. from lib389.properties import *
  14. from constants import *
  15. log = logging.getLogger(__name__)
  16. installation_prefix = None
  17. PROVISIONING_CN = "provisioning"
  18. PROVISIONING_DN = "cn=%s,%s" % (PROVISIONING_CN, SUFFIX)
  19. ACTIVE_CN = "accounts"
  20. STAGE_CN = "staged users"
  21. DELETE_CN = "deleted users"
  22. ACTIVE_DN = "cn=%s,%s" % (ACTIVE_CN, SUFFIX)
  23. STAGE_DN = "cn=%s,%s" % (STAGE_CN, PROVISIONING_DN)
  24. DELETE_DN = "cn=%s,%s" % (DELETE_CN, PROVISIONING_DN)
  25. STAGE_USER_CN = "stage guy"
  26. STAGE_USER_DN = "cn=%s,%s" % (STAGE_USER_CN, STAGE_DN)
  27. ACTIVE_USER_CN = "active guy"
  28. ACTIVE_USER_DN = "cn=%s,%s" % (ACTIVE_USER_CN, ACTIVE_DN)
  29. ACTIVE_USER_1_CN = "test_1"
  30. ACTIVE_USER_1_DN = "cn=%s,%s" % (ACTIVE_USER_1_CN, ACTIVE_DN)
  31. ACTIVE_USER_2_CN = "test_2"
  32. ACTIVE_USER_2_DN = "cn=%s,%s" % (ACTIVE_USER_2_CN, ACTIVE_DN)
  33. STAGE_USER_1_CN = ACTIVE_USER_1_CN
  34. STAGE_USER_1_DN = "cn=%s,%s" % (STAGE_USER_1_CN, STAGE_DN)
  35. STAGE_USER_2_CN = ACTIVE_USER_2_CN
  36. STAGE_USER_2_DN = "cn=%s,%s" % (STAGE_USER_2_CN, STAGE_DN)
  37. ALL_CONFIG_ATTRS = ['nsslapd-pluginarg0', 'nsslapd-pluginarg1', 'nsslapd-pluginarg2',
  38. 'uniqueness-attribute-name', 'uniqueness-subtrees', 'uniqueness-across-all-subtrees']
  39. class TopologyStandalone(object):
  40. def __init__(self, standalone):
  41. standalone.open()
  42. self.standalone = standalone
  43. @pytest.fixture(scope="module")
  44. def topology(request):
  45. '''
  46. This fixture is used to standalone topology for the 'module'.
  47. At the beginning, It may exists a standalone instance.
  48. It may also exists a backup for the standalone instance.
  49. Principle:
  50. If standalone instance exists:
  51. restart it
  52. If backup of standalone exists:
  53. create/rebind to standalone
  54. restore standalone instance from backup
  55. else:
  56. Cleanup everything
  57. remove instance
  58. remove backup
  59. Create instance
  60. Create backup
  61. '''
  62. global installation_prefix
  63. if installation_prefix:
  64. args_instance[SER_DEPLOYED_DIR] = installation_prefix
  65. standalone = DirSrv(verbose=False)
  66. # Args for the standalone instance
  67. args_instance[SER_HOST] = HOST_STANDALONE
  68. args_instance[SER_PORT] = PORT_STANDALONE
  69. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  70. args_standalone = args_instance.copy()
  71. standalone.allocate(args_standalone)
  72. # Get the status of the backups
  73. backup_standalone = standalone.checkBackupFS()
  74. # Get the status of the instance and restart it if it exists
  75. instance_standalone = standalone.exists()
  76. if instance_standalone:
  77. # assuming the instance is already stopped, just wait 5 sec max
  78. standalone.stop(timeout=5)
  79. try:
  80. standalone.start(timeout=10)
  81. except ldap.SERVER_DOWN:
  82. pass
  83. if backup_standalone:
  84. # The backup exist, assuming it is correct
  85. # we just re-init the instance with it
  86. if not instance_standalone:
  87. standalone.create()
  88. # Used to retrieve configuration information (dbdir, confdir...)
  89. standalone.open()
  90. # restore standalone instance from backup
  91. standalone.stop(timeout=10)
  92. standalone.restoreFS(backup_standalone)
  93. standalone.start(timeout=10)
  94. else:
  95. # We should be here only in two conditions
  96. # - This is the first time a test involve standalone instance
  97. # - Something weird happened (instance/backup destroyed)
  98. # so we discard everything and recreate all
  99. # Remove the backup. So even if we have a specific backup file
  100. # (e.g backup_standalone) we clear backup that an instance may have created
  101. if backup_standalone:
  102. standalone.clearBackupFS()
  103. # Remove the instance
  104. if instance_standalone:
  105. standalone.delete()
  106. # Create the instance
  107. standalone.create()
  108. # Used to retrieve configuration information (dbdir, confdir...)
  109. standalone.open()
  110. # Time to create the backups
  111. standalone.stop(timeout=10)
  112. standalone.backupfile = standalone.backupFS()
  113. standalone.start(timeout=10)
  114. # clear the tmp directory
  115. standalone.clearTmpDir(__file__)
  116. #
  117. # Here we have standalone instance up and running
  118. # Either coming from a backup recovery
  119. # or from a fresh (re)init
  120. # Time to return the topology
  121. return TopologyStandalone(standalone)
  122. def _header(topology, label):
  123. topology.standalone.log.info("\n\n###############################################")
  124. topology.standalone.log.info("#######")
  125. topology.standalone.log.info("####### %s" % label)
  126. topology.standalone.log.info("#######")
  127. topology.standalone.log.info("###############################################")
  128. def _uniqueness_config_entry(topology, name=None):
  129. if not name:
  130. return None
  131. ent = topology.standalone.getEntry("cn=%s,%s" % (PLUGIN_ATTR_UNIQUENESS, DN_PLUGIN), ldap.SCOPE_BASE,
  132. "(objectclass=nsSlapdPlugin)",
  133. ['objectClass', 'cn', 'nsslapd-pluginPath', 'nsslapd-pluginInitfunc',
  134. 'nsslapd-pluginType', 'nsslapd-pluginEnabled', 'nsslapd-plugin-depends-on-type',
  135. 'nsslapd-pluginId', 'nsslapd-pluginVersion', 'nsslapd-pluginVendor',
  136. 'nsslapd-pluginDescription'])
  137. ent.dn = "cn=%s uniqueness,%s" % (name, DN_PLUGIN)
  138. return ent
  139. def _build_config(topology, attr_name='cn', subtree_1=None, subtree_2=None, type_config='old', across_subtrees=False):
  140. assert topology
  141. assert attr_name
  142. assert subtree_1
  143. if type_config == 'old':
  144. # enable the 'cn' uniqueness on Active
  145. config = _uniqueness_config_entry(topology, attr_name)
  146. config.setValue('nsslapd-pluginarg0', attr_name)
  147. config.setValue('nsslapd-pluginarg1', subtree_1)
  148. if subtree_2:
  149. config.setValue('nsslapd-pluginarg2', subtree_2)
  150. else:
  151. # prepare the config entry
  152. config = _uniqueness_config_entry(topology, attr_name)
  153. config.setValue('uniqueness-attribute-name', attr_name)
  154. config.setValue('uniqueness-subtrees', subtree_1)
  155. if subtree_2:
  156. config.setValue('uniqueness-subtrees', subtree_2)
  157. if across_subtrees:
  158. config.setValue('uniqueness-across-all-subtrees', 'on')
  159. return config
  160. def _active_container_invalid_cfg_add(topology):
  161. '''
  162. Check uniqueness is not enforced with ADD (invalid config)
  163. '''
  164. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  165. 'objectclass': "top person".split(),
  166. 'sn': ACTIVE_USER_1_CN,
  167. 'cn': ACTIVE_USER_1_CN})))
  168. topology.standalone.add_s(Entry((ACTIVE_USER_2_DN, {
  169. 'objectclass': "top person".split(),
  170. 'sn': ACTIVE_USER_2_CN,
  171. 'cn': [ACTIVE_USER_1_CN, ACTIVE_USER_2_CN]})))
  172. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  173. topology.standalone.delete_s(ACTIVE_USER_2_DN)
  174. def _active_container_add(topology, type_config='old'):
  175. '''
  176. Check uniqueness in a single container (Active)
  177. Add an entry with a given 'cn', then check we can not add an entry with the same 'cn' value
  178. '''
  179. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config=type_config, across_subtrees=False)
  180. # remove the 'cn' uniqueness entry
  181. try:
  182. topology.standalone.delete_s(config.dn)
  183. except ldap.NO_SUCH_OBJECT:
  184. pass
  185. topology.standalone.restart(timeout=120)
  186. topology.standalone.log.info('Uniqueness not enforced: create the entries')
  187. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  188. 'objectclass': "top person".split(),
  189. 'sn': ACTIVE_USER_1_CN,
  190. 'cn': ACTIVE_USER_1_CN})))
  191. topology.standalone.add_s(Entry((ACTIVE_USER_2_DN, {
  192. 'objectclass': "top person".split(),
  193. 'sn': ACTIVE_USER_2_CN,
  194. 'cn': [ACTIVE_USER_1_CN, ACTIVE_USER_2_CN]})))
  195. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  196. topology.standalone.delete_s(ACTIVE_USER_2_DN)
  197. topology.standalone.log.info('Uniqueness enforced: checks second entry is rejected')
  198. # enable the 'cn' uniqueness on Active
  199. topology.standalone.add_s(config)
  200. topology.standalone.restart(timeout=120)
  201. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  202. 'objectclass': "top person".split(),
  203. 'sn': ACTIVE_USER_1_CN,
  204. 'cn': ACTIVE_USER_1_CN})))
  205. try:
  206. topology.standalone.add_s(Entry((ACTIVE_USER_2_DN, {
  207. 'objectclass': "top person".split(),
  208. 'sn': ACTIVE_USER_2_CN,
  209. 'cn': [ACTIVE_USER_1_CN, ACTIVE_USER_2_CN]})))
  210. except ldap.CONSTRAINT_VIOLATION:
  211. # yes it is expected
  212. pass
  213. # cleanup the stuff now
  214. topology.standalone.delete_s(config.dn)
  215. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  216. def _active_container_mod(topology, type_config='old'):
  217. '''
  218. Check uniqueness in a single container (active)
  219. Add and entry with a given 'cn', then check we can not modify an entry with the same 'cn' value
  220. '''
  221. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config=type_config, across_subtrees=False)
  222. # enable the 'cn' uniqueness on Active
  223. topology.standalone.add_s(config)
  224. topology.standalone.restart(timeout=120)
  225. topology.standalone.log.info('Uniqueness enforced: checks MOD ADD entry is rejected')
  226. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  227. 'objectclass': "top person".split(),
  228. 'sn': ACTIVE_USER_1_CN,
  229. 'cn': ACTIVE_USER_1_CN})))
  230. topology.standalone.add_s(Entry((ACTIVE_USER_2_DN, {
  231. 'objectclass': "top person".split(),
  232. 'sn': ACTIVE_USER_2_CN,
  233. 'cn': ACTIVE_USER_2_CN})))
  234. try:
  235. topology.standalone.modify_s(ACTIVE_USER_2_DN, [(ldap.MOD_ADD, 'cn', ACTIVE_USER_1_CN)])
  236. except ldap.CONSTRAINT_VIOLATION:
  237. # yes it is expected
  238. pass
  239. topology.standalone.log.info('Uniqueness enforced: checks MOD REPLACE entry is rejected')
  240. try:
  241. topology.standalone.modify_s(ACTIVE_USER_2_DN, [(ldap.MOD_REPLACE, 'cn', [ACTIVE_USER_1_CN, ACTIVE_USER_2_CN])])
  242. except ldap.CONSTRAINT_VIOLATION:
  243. # yes it is expected
  244. pass
  245. # cleanup the stuff now
  246. topology.standalone.delete_s(config.dn)
  247. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  248. topology.standalone.delete_s(ACTIVE_USER_2_DN)
  249. def _active_container_modrdn(topology, type_config='old'):
  250. '''
  251. Check uniqueness in a single container
  252. Add and entry with a given 'cn', then check we can not modrdn an entry with the same 'cn' value
  253. '''
  254. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config=type_config, across_subtrees=False)
  255. # enable the 'cn' uniqueness on Active
  256. topology.standalone.add_s(config)
  257. topology.standalone.restart(timeout=120)
  258. topology.standalone.log.info('Uniqueness enforced: checks MODRDN entry is rejected')
  259. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  260. 'objectclass': "top person".split(),
  261. 'sn': ACTIVE_USER_1_CN,
  262. 'cn': [ACTIVE_USER_1_CN, 'dummy']})))
  263. topology.standalone.add_s(Entry((ACTIVE_USER_2_DN, {
  264. 'objectclass': "top person".split(),
  265. 'sn': ACTIVE_USER_2_CN,
  266. 'cn': ACTIVE_USER_2_CN})))
  267. try:
  268. topology.standalone.rename_s(ACTIVE_USER_2_DN, 'cn=dummy', delold=0)
  269. except ldap.CONSTRAINT_VIOLATION:
  270. # yes it is expected
  271. pass
  272. # cleanup the stuff now
  273. topology.standalone.delete_s(config.dn)
  274. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  275. topology.standalone.delete_s(ACTIVE_USER_2_DN)
  276. def _active_stage_containers_add(topology, type_config='old', across_subtrees=False):
  277. '''
  278. Check uniqueness in several containers
  279. Add an entry on a container with a given 'cn'
  280. with across_subtrees=False check we CAN add an entry with the same 'cn' value on the other container
  281. with across_subtrees=True check we CAN NOT add an entry with the same 'cn' value on the other container
  282. '''
  283. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=STAGE_DN, type_config=type_config, across_subtrees=False)
  284. topology.standalone.add_s(config)
  285. topology.standalone.restart(timeout=120)
  286. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  287. 'objectclass': "top person".split(),
  288. 'sn': ACTIVE_USER_1_CN,
  289. 'cn': ACTIVE_USER_1_CN})))
  290. try:
  291. # adding an entry on a separated contains with the same 'cn'
  292. topology.standalone.add_s(Entry((STAGE_USER_1_DN, {
  293. 'objectclass': "top person".split(),
  294. 'sn': STAGE_USER_1_CN,
  295. 'cn': ACTIVE_USER_1_CN})))
  296. except ldap.CONSTRAINT_VIOLATION:
  297. assert across_subtrees
  298. # cleanup the stuff now
  299. topology.standalone.delete_s(config.dn)
  300. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  301. topology.standalone.delete_s(STAGE_USER_1_DN)
  302. def _active_stage_containers_mod(topology, type_config='old', across_subtrees=False):
  303. '''
  304. Check uniqueness in a several containers
  305. Add an entry on a container with a given 'cn', then check we CAN mod an entry with the same 'cn' value on the other container
  306. '''
  307. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=STAGE_DN, type_config=type_config, across_subtrees=False)
  308. topology.standalone.add_s(config)
  309. topology.standalone.restart(timeout=120)
  310. # adding an entry on active with a different 'cn'
  311. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  312. 'objectclass': "top person".split(),
  313. 'sn': ACTIVE_USER_1_CN,
  314. 'cn': ACTIVE_USER_2_CN})))
  315. # adding an entry on a stage with a different 'cn'
  316. topology.standalone.add_s(Entry((STAGE_USER_1_DN, {
  317. 'objectclass': "top person".split(),
  318. 'sn': STAGE_USER_1_CN,
  319. 'cn': STAGE_USER_1_CN})))
  320. try:
  321. # modify add same value
  322. topology.standalone.modify_s(STAGE_USER_1_DN, [(ldap.MOD_ADD, 'cn', [ACTIVE_USER_2_CN])])
  323. except ldap.CONSTRAINT_VIOLATION:
  324. assert across_subtrees
  325. topology.standalone.delete_s(STAGE_USER_1_DN)
  326. topology.standalone.add_s(Entry((STAGE_USER_1_DN, {
  327. 'objectclass': "top person".split(),
  328. 'sn': STAGE_USER_1_CN,
  329. 'cn': STAGE_USER_2_CN})))
  330. try:
  331. # modify replace same value
  332. topology.standalone.modify_s(STAGE_USER_1_DN, [(ldap.MOD_REPLACE, 'cn', [STAGE_USER_2_CN, ACTIVE_USER_1_CN])])
  333. except ldap.CONSTRAINT_VIOLATION:
  334. assert across_subtrees
  335. # cleanup the stuff now
  336. topology.standalone.delete_s(config.dn)
  337. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  338. topology.standalone.delete_s(STAGE_USER_1_DN)
  339. def _active_stage_containers_modrdn(topology, type_config='old', across_subtrees=False):
  340. '''
  341. Check uniqueness in a several containers
  342. Add and entry with a given 'cn', then check we CAN modrdn an entry with the same 'cn' value on the other container
  343. '''
  344. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=STAGE_DN, type_config=type_config, across_subtrees=False)
  345. # enable the 'cn' uniqueness on Active and Stage
  346. topology.standalone.add_s(config)
  347. topology.standalone.restart(timeout=120)
  348. topology.standalone.add_s(Entry((ACTIVE_USER_1_DN, {
  349. 'objectclass': "top person".split(),
  350. 'sn': ACTIVE_USER_1_CN,
  351. 'cn': [ACTIVE_USER_1_CN, 'dummy']})))
  352. topology.standalone.add_s(Entry((STAGE_USER_1_DN, {
  353. 'objectclass': "top person".split(),
  354. 'sn': STAGE_USER_1_CN,
  355. 'cn': STAGE_USER_1_CN})))
  356. try:
  357. topology.standalone.rename_s(STAGE_USER_1_DN, 'cn=dummy', delold=0)
  358. # check stage entry has 'cn=dummy'
  359. stage_ent = topology.standalone.getEntry("cn=dummy,%s" % (STAGE_DN), ldap.SCOPE_BASE, "objectclass=*", ['cn'])
  360. assert stage_ent.hasAttr('cn')
  361. found = False
  362. for value in stage_ent.getValues('cn'):
  363. if value == 'dummy':
  364. found = True
  365. assert found
  366. # check active entry has 'cn=dummy'
  367. active_ent = topology.standalone.getEntry(ACTIVE_USER_1_DN, ldap.SCOPE_BASE, "objectclass=*", ['cn'])
  368. assert active_ent.hasAttr('cn')
  369. found = False
  370. for value in stage_ent.getValues('cn'):
  371. if value == 'dummy':
  372. found = True
  373. assert found
  374. topology.standalone.delete_s("cn=dummy,%s" % (STAGE_DN))
  375. except ldap.CONSTRAINT_VIOLATION:
  376. assert across_subtrees
  377. topology.standalone.delete_s(STAGE_USER_1_DN)
  378. # cleanup the stuff now
  379. topology.standalone.delete_s(config.dn)
  380. topology.standalone.delete_s(ACTIVE_USER_1_DN)
  381. def _config_file(topology, action='save'):
  382. dse_ldif = topology.standalone.confdir + '/dse.ldif'
  383. sav_file = topology.standalone.confdir + '/dse.ldif.ticket47823'
  384. if action == 'save':
  385. shutil.copy(dse_ldif, sav_file)
  386. else:
  387. shutil.copy(sav_file, dse_ldif)
  388. def _pattern_errorlog(file, log_pattern):
  389. try:
  390. _pattern_errorlog.last_pos += 1
  391. except AttributeError:
  392. _pattern_errorlog.last_pos = 0
  393. found = None
  394. log.debug("_pattern_errorlog: start at offset %d" % _pattern_errorlog.last_pos)
  395. file.seek(_pattern_errorlog.last_pos)
  396. # Use a while true iteration because 'for line in file: hit a
  397. # python bug that break file.tell()
  398. while True:
  399. line = file.readline()
  400. log.debug("_pattern_errorlog: [%d] %s" % (file.tell(), line))
  401. found = log_pattern.search(line)
  402. if ((line == '') or (found)):
  403. break
  404. log.debug("_pattern_errorlog: end at offset %d" % file.tell())
  405. _pattern_errorlog.last_pos = file.tell()
  406. return found
  407. def test_ticket47823_init(topology):
  408. """
  409. """
  410. # Enabled the plugins
  411. topology.standalone.plugins.enable(name=PLUGIN_ATTR_UNIQUENESS)
  412. topology.standalone.restart(timeout=120)
  413. topology.standalone.add_s(Entry((PROVISIONING_DN, {'objectclass': "top nscontainer".split(),
  414. 'cn': PROVISIONING_CN})))
  415. topology.standalone.add_s(Entry((ACTIVE_DN, {'objectclass': "top nscontainer".split(),
  416. 'cn': ACTIVE_CN})))
  417. topology.standalone.add_s(Entry((STAGE_DN, {'objectclass': "top nscontainer".split(),
  418. 'cn': STAGE_CN})))
  419. topology.standalone.add_s(Entry((DELETE_DN, {'objectclass': "top nscontainer".split(),
  420. 'cn': DELETE_CN})))
  421. topology.standalone.errorlog_file = open(topology.standalone.errlog, "r")
  422. topology.standalone.stop(timeout=120)
  423. time.sleep(1)
  424. topology.standalone.start(timeout=120)
  425. time.sleep(3)
  426. def test_ticket47823_one_container_add(topology):
  427. '''
  428. Check uniqueness in a single container
  429. Add and entry with a given 'cn', then check we can not add an entry with the same 'cn' value
  430. '''
  431. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (ADD) ")
  432. _active_container_add(topology, type_config='old')
  433. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (ADD) ")
  434. _active_container_add(topology, type_config='new')
  435. def test_ticket47823_one_container_mod(topology):
  436. '''
  437. Check uniqueness in a single container
  438. Add and entry with a given 'cn', then check we can not modify an entry with the same 'cn' value
  439. '''
  440. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (MOD)")
  441. _active_container_mod(topology, type_config='old')
  442. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (MOD)")
  443. _active_container_mod(topology, type_config='new')
  444. def test_ticket47823_one_container_modrdn(topology):
  445. '''
  446. Check uniqueness in a single container
  447. Add and entry with a given 'cn', then check we can not modrdn an entry with the same 'cn' value
  448. '''
  449. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (MODRDN)")
  450. _active_container_modrdn(topology, type_config='old')
  451. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (MODRDN)")
  452. _active_container_modrdn(topology, type_config='new')
  453. def test_ticket47823_multi_containers_add(topology):
  454. '''
  455. Check uniqueness in a several containers
  456. Add and entry with a given 'cn', then check we can not add an entry with the same 'cn' value
  457. '''
  458. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (ADD) ")
  459. _active_stage_containers_add(topology, type_config='old', across_subtrees=False)
  460. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (ADD) ")
  461. _active_stage_containers_add(topology, type_config='new', across_subtrees=False)
  462. def test_ticket47823_multi_containers_mod(topology):
  463. '''
  464. Check uniqueness in a several containers
  465. Add an entry on a container with a given 'cn', then check we CAN mod an entry with the same 'cn' value on the other container
  466. '''
  467. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (MOD) on separated container")
  468. topology.standalone.log.info('Uniqueness not enforced: if same \'cn\' modified (add/replace) on separated containers')
  469. _active_stage_containers_mod(topology, type_config='old', across_subtrees=False)
  470. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (MOD) on separated container")
  471. topology.standalone.log.info('Uniqueness not enforced: if same \'cn\' modified (add/replace) on separated containers')
  472. _active_stage_containers_mod(topology, type_config='new', across_subtrees=False)
  473. def test_ticket47823_multi_containers_modrdn(topology):
  474. '''
  475. Check uniqueness in a several containers
  476. Add and entry with a given 'cn', then check we CAN modrdn an entry with the same 'cn' value on the other container
  477. '''
  478. _header(topology, "With former config (args), check attribute uniqueness with 'cn' (MODRDN) on separated containers")
  479. topology.standalone.log.info('Uniqueness not enforced: checks MODRDN entry is accepted on separated containers')
  480. _active_stage_containers_modrdn(topology, type_config='old', across_subtrees=False)
  481. topology.standalone.log.info('Uniqueness not enforced: checks MODRDN entry is accepted on separated containers')
  482. _active_stage_containers_modrdn(topology, type_config='old')
  483. def test_ticket47823_across_multi_containers_add(topology):
  484. '''
  485. Check uniqueness across several containers, uniquely with the new configuration
  486. Add and entry with a given 'cn', then check we can not add an entry with the same 'cn' value
  487. '''
  488. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (ADD) across several containers")
  489. _active_stage_containers_add(topology, type_config='old', across_subtrees=True)
  490. def test_ticket47823_across_multi_containers_mod(topology):
  491. '''
  492. Check uniqueness across several containers, uniquely with the new configuration
  493. Add and entry with a given 'cn', then check we can not modifiy an entry with the same 'cn' value
  494. '''
  495. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (MOD) across several containers")
  496. _active_stage_containers_mod(topology, type_config='old', across_subtrees=True)
  497. def test_ticket47823_across_multi_containers_modrdn(topology):
  498. '''
  499. Check uniqueness across several containers, uniquely with the new configuration
  500. Add and entry with a given 'cn', then check we can not modrdn an entry with the same 'cn' value
  501. '''
  502. _header(topology, "With new config (args), check attribute uniqueness with 'cn' (MODRDN) across several containers")
  503. _active_stage_containers_modrdn(topology, type_config='old', across_subtrees=True)
  504. def test_ticket47823_invalid_config_1(topology):
  505. '''
  506. Check that an invalid config is detected. No uniqueness enforced
  507. Using old config: arg0 is missing
  508. '''
  509. _header(topology, "Invalid config (old): arg0 is missing")
  510. _config_file(topology, action='save')
  511. # create an invalid config without arg0
  512. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='old', across_subtrees=False)
  513. del config.data['nsslapd-pluginarg0']
  514. # replace 'cn' uniqueness entry
  515. try:
  516. topology.standalone.delete_s(config.dn)
  517. except ldap.NO_SUCH_OBJECT:
  518. pass
  519. topology.standalone.add_s(config)
  520. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  521. # Check the server did not restart
  522. try:
  523. topology.standalone.restart(timeout=5)
  524. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  525. if ent:
  526. # be sure to restore a valid config before assert
  527. _config_file(topology, action='restore')
  528. assert not ent
  529. except ldap.SERVER_DOWN:
  530. pass
  531. # Check the expected error message
  532. regex = re.compile("Config info: attribute name not defined")
  533. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  534. if not res:
  535. # be sure to restore a valid config before assert
  536. _config_file(topology, action='restore')
  537. assert res
  538. # Check we can restart the server
  539. _config_file(topology, action='restore')
  540. topology.standalone.start(timeout=5)
  541. try:
  542. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  543. except ldap.NO_SUCH_OBJECT:
  544. pass
  545. def test_ticket47823_invalid_config_2(topology):
  546. '''
  547. Check that an invalid config is detected. No uniqueness enforced
  548. Using old config: arg1 is missing
  549. '''
  550. _header(topology, "Invalid config (old): arg1 is missing")
  551. _config_file(topology, action='save')
  552. # create an invalid config without arg0
  553. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='old', across_subtrees=False)
  554. del config.data['nsslapd-pluginarg1']
  555. # replace 'cn' uniqueness entry
  556. try:
  557. topology.standalone.delete_s(config.dn)
  558. except ldap.NO_SUCH_OBJECT:
  559. pass
  560. topology.standalone.add_s(config)
  561. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  562. # Check the server did not restart
  563. try:
  564. topology.standalone.restart(timeout=5)
  565. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  566. if ent:
  567. # be sure to restore a valid config before assert
  568. _config_file(topology, action='restore')
  569. assert not ent
  570. except ldap.SERVER_DOWN:
  571. pass
  572. # Check the expected error message
  573. regex = re.compile("Config info: No valid subtree is defined")
  574. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  575. if not res:
  576. # be sure to restore a valid config before assert
  577. _config_file(topology, action='restore')
  578. assert res
  579. # Check we can restart the server
  580. _config_file(topology, action='restore')
  581. topology.standalone.start(timeout=5)
  582. try:
  583. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  584. except ldap.NO_SUCH_OBJECT:
  585. pass
  586. def test_ticket47823_invalid_config_3(topology):
  587. '''
  588. Check that an invalid config is detected. No uniqueness enforced
  589. Using old config: arg0 is missing
  590. '''
  591. _header(topology, "Invalid config (old): arg0 is missing but new config attrname exists")
  592. _config_file(topology, action='save')
  593. # create an invalid config without arg0
  594. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='old', across_subtrees=False)
  595. del config.data['nsslapd-pluginarg0']
  596. config.data['uniqueness-attribute-name'] = 'cn'
  597. # replace 'cn' uniqueness entry
  598. try:
  599. topology.standalone.delete_s(config.dn)
  600. except ldap.NO_SUCH_OBJECT:
  601. pass
  602. topology.standalone.add_s(config)
  603. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  604. # Check the server did not restart
  605. try:
  606. topology.standalone.restart(timeout=5)
  607. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  608. if ent:
  609. # be sure to restore a valid config before assert
  610. _config_file(topology, action='restore')
  611. assert not ent
  612. except ldap.SERVER_DOWN:
  613. pass
  614. # Check the expected error message
  615. regex = re.compile("Config info: objectclass for subtree entries is not defined")
  616. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  617. if not res:
  618. # be sure to restore a valid config before assert
  619. _config_file(topology, action='restore')
  620. assert res
  621. # Check we can restart the server
  622. _config_file(topology, action='restore')
  623. topology.standalone.start(timeout=5)
  624. try:
  625. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  626. except ldap.NO_SUCH_OBJECT:
  627. pass
  628. def test_ticket47823_invalid_config_4(topology):
  629. '''
  630. Check that an invalid config is detected. No uniqueness enforced
  631. Using old config: arg1 is missing
  632. '''
  633. _header(topology, "Invalid config (old): arg1 is missing but new config exist")
  634. _config_file(topology, action='save')
  635. # create an invalid config without arg0
  636. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='old', across_subtrees=False)
  637. del config.data['nsslapd-pluginarg1']
  638. config.data['uniqueness-subtrees'] = ACTIVE_DN
  639. # replace 'cn' uniqueness entry
  640. try:
  641. topology.standalone.delete_s(config.dn)
  642. except ldap.NO_SUCH_OBJECT:
  643. pass
  644. topology.standalone.add_s(config)
  645. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  646. # Check the server did not restart
  647. try:
  648. topology.standalone.restart(timeout=5)
  649. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  650. if ent:
  651. # be sure to restore a valid config before assert
  652. _config_file(topology, action='restore')
  653. assert not ent
  654. except ldap.SERVER_DOWN:
  655. pass
  656. # Check the expected error message
  657. regex = re.compile("Config info: No valid subtree is defined")
  658. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  659. if not res:
  660. # be sure to restore a valid config before assert
  661. _config_file(topology, action='restore')
  662. assert res
  663. # Check we can restart the server
  664. _config_file(topology, action='restore')
  665. topology.standalone.start(timeout=5)
  666. try:
  667. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  668. except ldap.NO_SUCH_OBJECT:
  669. pass
  670. def test_ticket47823_invalid_config_5(topology):
  671. '''
  672. Check that an invalid config is detected. No uniqueness enforced
  673. Using new config: uniqueness-attribute-name is missing
  674. '''
  675. _header(topology, "Invalid config (new): uniqueness-attribute-name is missing")
  676. _config_file(topology, action='save')
  677. # create an invalid config without arg0
  678. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='new', across_subtrees=False)
  679. del config.data['uniqueness-attribute-name']
  680. # replace 'cn' uniqueness entry
  681. try:
  682. topology.standalone.delete_s(config.dn)
  683. except ldap.NO_SUCH_OBJECT:
  684. pass
  685. topology.standalone.add_s(config)
  686. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  687. # Check the server did not restart
  688. try:
  689. topology.standalone.restart(timeout=5)
  690. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  691. if ent:
  692. # be sure to restore a valid config before assert
  693. _config_file(topology, action='restore')
  694. assert not ent
  695. except ldap.SERVER_DOWN:
  696. pass
  697. # Check the expected error message
  698. regex = re.compile("Config info: attribute name not defined")
  699. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  700. if not res:
  701. # be sure to restore a valid config before assert
  702. _config_file(topology, action='restore')
  703. assert res
  704. # Check we can restart the server
  705. _config_file(topology, action='restore')
  706. topology.standalone.start(timeout=5)
  707. try:
  708. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  709. except ldap.NO_SUCH_OBJECT:
  710. pass
  711. def test_ticket47823_invalid_config_6(topology):
  712. '''
  713. Check that an invalid config is detected. No uniqueness enforced
  714. Using new config: uniqueness-subtrees is missing
  715. '''
  716. _header(topology, "Invalid config (new): uniqueness-subtrees is missing")
  717. _config_file(topology, action='save')
  718. # create an invalid config without arg0
  719. config = _build_config(topology, attr_name='cn', subtree_1=ACTIVE_DN, subtree_2=None, type_config='new', across_subtrees=False)
  720. del config.data['uniqueness-subtrees']
  721. # replace 'cn' uniqueness entry
  722. try:
  723. topology.standalone.delete_s(config.dn)
  724. except ldap.NO_SUCH_OBJECT:
  725. pass
  726. topology.standalone.add_s(config)
  727. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  728. # Check the server did not restart
  729. try:
  730. topology.standalone.restart(timeout=5)
  731. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  732. if ent:
  733. # be sure to restore a valid config before assert
  734. _config_file(topology, action='restore')
  735. assert not ent
  736. except ldap.SERVER_DOWN:
  737. pass
  738. # Check the expected error message
  739. regex = re.compile("Config info: objectclass for subtree entries is not defined")
  740. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  741. if not res:
  742. # be sure to restore a valid config before assert
  743. _config_file(topology, action='restore')
  744. assert res
  745. # Check we can restart the server
  746. _config_file(topology, action='restore')
  747. topology.standalone.start(timeout=5)
  748. try:
  749. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  750. except ldap.NO_SUCH_OBJECT:
  751. pass
  752. def test_ticket47823_invalid_config_7(topology):
  753. '''
  754. Check that an invalid config is detected. No uniqueness enforced
  755. Using new config: uniqueness-subtrees is missing
  756. '''
  757. _header(topology, "Invalid config (new): uniqueness-subtrees are invalid")
  758. _config_file(topology, action='save')
  759. # create an invalid config without arg0
  760. config = _build_config(topology, attr_name='cn', subtree_1="this_is dummy DN", subtree_2="an other=dummy DN", type_config='new', across_subtrees=False)
  761. # replace 'cn' uniqueness entry
  762. try:
  763. topology.standalone.delete_s(config.dn)
  764. except ldap.NO_SUCH_OBJECT:
  765. pass
  766. topology.standalone.add_s(config)
  767. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  768. # Check the server did not restart
  769. try:
  770. topology.standalone.restart(timeout=5)
  771. ent = topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  772. if ent:
  773. # be sure to restore a valid config before assert
  774. _config_file(topology, action='restore')
  775. assert not ent
  776. except ldap.SERVER_DOWN:
  777. pass
  778. # Check the expected error message
  779. regex = re.compile("Config info: No valid subtree is defined")
  780. res =_pattern_errorlog(topology.standalone.errorlog_file, regex)
  781. if not res:
  782. # be sure to restore a valid config before assert
  783. _config_file(topology, action='restore')
  784. assert res
  785. # Check we can restart the server
  786. _config_file(topology, action='restore')
  787. topology.standalone.start(timeout=5)
  788. try:
  789. topology.standalone.getEntry(config.dn, ldap.SCOPE_BASE, "(objectclass=nsSlapdPlugin)", ALL_CONFIG_ATTRS)
  790. except ldap.NO_SUCH_OBJECT:
  791. pass
  792. def test_ticket47823_final(topology):
  793. topology.standalone.stop(timeout=10)
  794. def run_isolated():
  795. '''
  796. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  797. To run isolated without py.test, you need to
  798. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  799. - set the installation prefix
  800. - run this program
  801. '''
  802. global installation_prefix
  803. installation_prefix = None
  804. topo = topology(True)
  805. test_ticket47823_init(topo)
  806. # run old/new config style that makes uniqueness checking on one subtree
  807. test_ticket47823_one_container_add(topo)
  808. test_ticket47823_one_container_mod(topo)
  809. test_ticket47823_one_container_modrdn(topo)
  810. # run old config style that makes uniqueness checking on each defined subtrees
  811. test_ticket47823_multi_containers_add(topo)
  812. test_ticket47823_multi_containers_mod(topo)
  813. test_ticket47823_multi_containers_modrdn(topo)
  814. test_ticket47823_across_multi_containers_add(topo)
  815. test_ticket47823_across_multi_containers_mod(topo)
  816. test_ticket47823_across_multi_containers_modrdn(topo)
  817. test_ticket47823_invalid_config_1(topo)
  818. test_ticket47823_invalid_config_2(topo)
  819. test_ticket47823_invalid_config_3(topo)
  820. test_ticket47823_invalid_config_4(topo)
  821. test_ticket47823_invalid_config_5(topo)
  822. test_ticket47823_invalid_config_6(topo)
  823. test_ticket47823_invalid_config_7(topo)
  824. test_ticket47823_final(topo)
  825. if __name__ == '__main__':
  826. run_isolated()