ticket47823_test.py 38 KB

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