001/*
002 * Copyright 2011-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2011-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2011-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.util;
037
038
039
040import java.util.ArrayList;
041import java.util.Arrays;
042import java.util.Collection;
043import java.util.List;
044
045import com.unboundid.ldap.matchingrules.DistinguishedNameMatchingRule;
046import com.unboundid.ldap.sdk.Attribute;
047import com.unboundid.ldap.sdk.Control;
048import com.unboundid.ldap.sdk.DN;
049import com.unboundid.ldap.sdk.Entry;
050import com.unboundid.ldap.sdk.Filter;
051import com.unboundid.ldap.sdk.LDAPConnection;
052import com.unboundid.ldap.sdk.LDAPException;
053import com.unboundid.ldap.sdk.LDAPInterface;
054import com.unboundid.ldap.sdk.LDAPRequest;
055import com.unboundid.ldap.sdk.LDAPResult;
056import com.unboundid.ldap.sdk.LDAPSearchException;
057import com.unboundid.ldap.sdk.RDN;
058import com.unboundid.ldap.sdk.ResultCode;
059import com.unboundid.ldap.sdk.SearchResult;
060import com.unboundid.ldap.sdk.SearchResultEntry;
061import com.unboundid.ldap.sdk.SearchResultReference;
062import com.unboundid.ldap.sdk.SearchScope;
063
064import static com.unboundid.util.UtilityMessages.*;
065
066
067
068/**
069 * This class provides a number of convenience methods that can be used to help
070 * write test cases for directory-enabled applications.
071 */
072@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
073public final class LDAPTestUtils
074{
075  /**
076   * Ensure that this utility class cannot be instantiated.
077   */
078  private LDAPTestUtils()
079  {
080    // No implementation required.
081  }
082
083
084
085  /**
086   * Generates a domain entry with the provided information.  It will include
087   * the top and domain object classes and will use dc as the RDN attribute.  It
088   * may optionally include additional attributes.
089   *
090   * @param  name                  The name for the domain, which will be used
091   *                               as the value of the "dc" attribute.  It must
092   *                               not be {@code null}.
093   * @param  parentDN              The DN of the entry below which the new
094   *                               entry should be placed.  It may be
095   *                               {@code null} if the new entry should not have
096   *                               a parent.
097   * @param  additionalAttributes  A set of additional attributes to include in
098   *                               the generated entry.  It may be {@code null}
099   *                               or empty if no additional attributes should
100   *                               be included.
101   *
102   * @return  The generated entry.
103   */
104  @NotNull()
105  public static Entry generateDomainEntry(@NotNull final String name,
106                           @Nullable final String parentDN,
107                           @Nullable final Attribute... additionalAttributes)
108  {
109    return generateDomainEntry(name, parentDN,
110         StaticUtils.toList(additionalAttributes));
111  }
112
113
114
115  /**
116   * Generates a domain entry with the provided information.  It will include
117   * the top and domain object classes and will use dc as the RDN attribute.  It
118   * may optionally include additional attributes.
119   *
120   * @param  name                  The name for the domain, which will be used
121   *                               as the value of the "dc" attribute.  It must
122   *                               not be {@code null}.
123   * @param  parentDN              The DN of the entry below which the new
124   *                               entry should be placed.  It may be
125   *                               {@code null} if the new entry should not have
126   *                               a parent.
127   * @param  additionalAttributes  A set of additional attributes to include in
128   *                               the generated entry.  It may be {@code null}
129   *                               or empty if no additional attributes should
130   *                               be included.
131   *
132   * @return  The generated entry.
133   */
134  @NotNull()
135  public static Entry generateDomainEntry(@NotNull final String name,
136              @Nullable final String parentDN,
137              @Nullable final Collection<Attribute> additionalAttributes)
138  {
139    return generateEntry("dc", name, parentDN, new String[] { "top", "domain" },
140         additionalAttributes);
141  }
142
143
144
145  /**
146   * Generates an organization entry with the provided information.  It will
147   * include the top and organization object classes and will use o as the RDN
148   * attribute.  It may optionally include additional attributes.
149   *
150   * @param  name                  The name for the organization, which will be
151   *                               used as the value of the "o" attribute.  It
152   *                               must not be {@code null}.
153   * @param  parentDN              The DN of the entry below which the new
154   *                               entry should be placed.  It may be
155   *                               {@code null} if the new entry should not have
156   *                               a parent.
157   * @param  additionalAttributes  A set of additional attributes to include in
158   *                               the generated entry.  It may be {@code null}
159   *                               or empty if no additional attributes should
160   *                               be included.
161   *
162   * @return  The generated entry.
163   */
164  @NotNull()
165  public static Entry generateOrgEntry(@NotNull final String name,
166                           @Nullable final String parentDN,
167                           @Nullable final Attribute... additionalAttributes)
168  {
169    return generateOrgEntry(name, parentDN,
170         StaticUtils.toList(additionalAttributes));
171  }
172
173
174
175  /**
176   * Generates an organization entry with the provided information.  It will
177   * include the top and organization object classes and will use o as the RDN
178   * attribute.  It may optionally include additional attributes.
179   *
180   * @param  name                  The name for the organization, which will be
181   *                               used as the value of the "o" attribute.  It
182   *                               must not be {@code null}.
183   * @param  parentDN              The DN of the entry below which the new
184   *                               entry should be placed.  It may be
185   *                               {@code null} if the new entry should not have
186   *                               a parent.
187   * @param  additionalAttributes  A set of additional attributes to include in
188   *                               the generated entry.  It may be {@code null}
189   *                               or empty if no additional attributes should
190   *                               be included.
191   *
192   * @return  The generated entry.
193   */
194  @NotNull()
195  public static Entry generateOrgEntry(@NotNull final String name,
196              @Nullable final String parentDN,
197              @Nullable final Collection<Attribute> additionalAttributes)
198  {
199    return generateEntry("o", name, parentDN,
200         new String[] { "top", "organization" },
201         additionalAttributes);
202  }
203
204
205
206  /**
207   * Generates an organizationalUnit entry with the provided information.  It
208   * will include the top and organizationalUnit object classes and will use ou
209   * as the RDN attribute.  It may optionally include additional attributes.
210   *
211   * @param  name                  The name for the organizationalUnit, which
212   *                               will be used as the value of the "ou"
213   *                               attribute.  It must not be {@code null}.
214   * @param  parentDN              The DN of the entry below which the new
215   *                               entry should be placed.  It may be
216   *                               {@code null} if the new entry should not have
217   *                               a parent.
218   * @param  additionalAttributes  A set of additional attributes to include in
219   *                               the generated entry.  It may be {@code null}
220   *                               or empty if no additional attributes should
221   *                               be included.
222   *
223   * @return  The generated entry.
224   */
225  @NotNull()
226  public static Entry generateOrgUnitEntry(@NotNull final String name,
227                           @Nullable final String parentDN,
228                           @Nullable final Attribute... additionalAttributes)
229  {
230    return generateOrgUnitEntry(name, parentDN,
231         StaticUtils.toList(additionalAttributes));
232  }
233
234
235
236  /**
237   * Generates an organizationalUnit entry with the provided information.  It
238   * will include the top and organizationalUnit object classes and will use ou
239   * as the RDN attribute.  It may optionally include additional attributes.
240   *
241   * @param  name                  The name for the organizationalUnit, which
242   *                               will be used as the value of the "ou"
243   *                               attribute.  It must not be {@code null}.
244   * @param  parentDN              The DN of the entry below which the new
245   *                               entry should be placed.  It may be
246   *                               {@code null} if the new entry should not have
247   *                               a parent.
248   * @param  additionalAttributes  A set of additional attributes to include in
249   *                               the generated entry.  It may be {@code null}
250   *                               or empty if no additional attributes should
251   *                               be included.
252   *
253   * @return  The generated entry.
254   */
255  @NotNull()
256  public static Entry generateOrgUnitEntry(@NotNull final String name,
257              @Nullable final String parentDN,
258              @Nullable final Collection<Attribute> additionalAttributes)
259  {
260    return generateEntry("ou", name, parentDN,
261         new String[] { "top", "organizationalUnit" },
262         additionalAttributes);
263  }
264
265
266
267  /**
268   * Generates a country entry with the provided information.  It will include
269   * the top and country object classes and will use c as the RDN attribute.  It
270   * may optionally include additional attributes.
271   *
272   * @param  name                  The name for the country (typically a
273   *                               two-character country code), which will be
274   *                               used as the value of the "c" attribute.  It
275   *                               must not be {@code null}.
276   * @param  parentDN              The DN of the entry below which the new
277   *                               entry should be placed.  It may be
278   *                               {@code null} if the new entry should not have
279   *                               a parent.
280   * @param  additionalAttributes  A set of additional attributes to include in
281   *                               the generated entry.  It may be {@code null}
282   *                               or empty if no additional attributes should
283   *                               be included.
284   *
285   * @return  The generated entry.
286   */
287  @NotNull()
288  public static Entry generateCountryEntry(@NotNull final String name,
289                           @Nullable final String parentDN,
290                           @Nullable final Attribute... additionalAttributes)
291  {
292    return generateCountryEntry(name, parentDN,
293         StaticUtils.toList(additionalAttributes));
294  }
295
296
297
298  /**
299   * Generates a country entry with the provided information.  It will include
300   * the top and country object classes and will use c as the RDN attribute.  It
301   * may optionally include additional attributes.
302   *
303   * @param  name                  The name for the country (typically a
304   *                               two-character country code), which will be
305   *                               used as the value of the "c" attribute.  It
306   *                               must not be {@code null}.
307   * @param  parentDN              The DN of the entry below which the new
308   *                               entry should be placed.  It may be
309   *                               {@code null} if the new entry should not have
310   *                               a parent.
311   * @param  additionalAttributes  A set of additional attributes to include in
312   *                               the generated entry.  It may be {@code null}
313   *                               or empty if no additional attributes should
314   *                               be included.
315   *
316   * @return  The generated entry.
317   */
318  @NotNull()
319  public static Entry generateCountryEntry(@NotNull final String name,
320              @Nullable final String parentDN,
321              @Nullable final Collection<Attribute> additionalAttributes)
322  {
323    return generateEntry("c", name, parentDN,
324         new String[] { "top", "country" },
325         additionalAttributes);
326  }
327
328
329
330  /**
331   * Generates a user entry with the provided information.  It will include the
332   * top, person, organizationalPerson, and inetOrgPerson object classes, will
333   * use uid as the RDN attribute, and will have givenName, sn, and cn
334   * attributes.  It may optionally include additional attributes.
335   *
336   * @param  uid                   The value to use for the "uid: attribute.  It
337   *                               must not be {@code null}.
338   * @param  parentDN              The DN of the entry below which the new
339   *                               entry should be placed.  It may be
340   *                               {@code null} if the new entry should not have
341   *                               a parent.
342   * @param  firstName             The first name for the user.  It must not be
343   *                               {@code null}.
344   * @param  lastName              The last name for the user.  It must not be
345   *                               {@code null}.
346   * @param  password              The password for the user.  It may be
347   *                               {@code null} if the user should not have a
348   *                               password.
349   * @param  additionalAttributes  A set of additional attributes to include in
350   *                               the generated entry.  It may be {@code null}
351   *                               or empty if no additional attributes should
352   *                               be included.
353   *
354   * @return  The generated entry.
355   */
356  @NotNull()
357  public static Entry generateUserEntry(@NotNull final String uid,
358              @Nullable final String parentDN, @NotNull final String firstName,
359              @NotNull final String lastName, @Nullable final String password,
360              @Nullable final Attribute... additionalAttributes)
361  {
362    return generateUserEntry(uid, parentDN, firstName, lastName, password,
363         StaticUtils.toList(additionalAttributes));
364  }
365
366
367
368  /**
369   * Generates a user entry with the provided information.  It will include the
370   * top, person, organizationalPerson, and inetOrgPerson object classes, will
371   * use uid as the RDN attribute, and will have givenName, sn, and cn
372   * attributes.  It may optionally include additional attributes.
373   *
374   * @param  uid                   The value to use for the "uid: attribute.  It
375   *                               must not be {@code null}.
376   * @param  parentDN              The DN of the entry below which the new
377   *                               entry should be placed.  It may be
378   *                               {@code null} if the new entry should not have
379   *                               a parent.
380   * @param  firstName             The first name for the user.  It must not be
381   *                               {@code null}.
382   * @param  lastName              The last name for the user.  It must not be
383   *                               {@code null}.
384   * @param  password              The password for the user.  It may be
385   *                               {@code null} if the user should not have a
386   *                               password.
387   * @param  additionalAttributes  A set of additional attributes to include in
388   *                               the generated entry.  It may be {@code null}
389   *                               or empty if no additional attributes should
390   *                               be included.
391   *
392   * @return  The generated entry.
393   */
394  @NotNull()
395  public static Entry generateUserEntry(@NotNull final String uid,
396              @Nullable final String parentDN,
397              @NotNull final String firstName,
398              @NotNull final String lastName,
399              @Nullable final String password,
400              @Nullable final Collection<Attribute> additionalAttributes)
401  {
402    final List<Attribute> attrList = new ArrayList<>(4);
403    attrList.add(new Attribute("givenName", firstName));
404    attrList.add(new Attribute("sn", lastName));
405    attrList.add(new Attribute("cn", firstName + ' ' + lastName));
406
407    if (password != null)
408    {
409      attrList.add(new Attribute("userPassword", password));
410    }
411
412    if (additionalAttributes != null)
413    {
414      attrList.addAll(additionalAttributes);
415    }
416
417    final String[] objectClasses =
418    {
419      "top",
420      "person",
421      "organizationalPerson",
422      "inetOrgPerson",
423    };
424
425    return generateEntry("uid", uid, parentDN, objectClasses, attrList);
426  }
427
428
429
430  /**
431   * Generates a group entry with the provided information.  It will include
432   * the top and groupOfNames object classes and will use cn as the RDN
433   * attribute.
434   *
435   * @param  name       The name for the group, which will be used as the value
436   *                    of the "cn" attribute.  It must not be {@code null}.
437   * @param  parentDN   The DN of the entry below which the new entry should be
438   *                    placed.  It may be {@code null} if the new entry should
439   *                    not have a parent.
440   * @param  memberDNs  The DNs of the users that should be listed as members of
441   *                    the group.
442   *
443   * @return  The generated entry.
444   */
445  @NotNull()
446  public static Entry generateGroupOfNamesEntry(@NotNull final String name,
447                           @Nullable final String parentDN,
448                           @NotNull final String... memberDNs)
449  {
450    return generateGroupOfNamesEntry(name, parentDN,
451         StaticUtils.toList(memberDNs));
452  }
453
454
455
456  /**
457   * Generates a group entry with the provided information.  It will include
458   * the top and groupOfNames object classes and will use cn as the RDN
459   * attribute.
460   *
461   * @param  name       The name for the group, which will be used as the value
462   *                    of the "cn" attribute.  It must not be {@code null}.
463   * @param  parentDN   The DN of the entry below which the new entry should be
464   *                    placed.  It may be {@code null} if the new entry should
465   *                    not have a parent.
466   * @param  memberDNs  The DNs of the users that should be listed as members of
467   *                    the group.
468   *
469   * @return  The generated entry.
470   */
471  @NotNull()
472  public static Entry generateGroupOfNamesEntry(@NotNull final String name,
473                           @Nullable final String parentDN,
474                           @NotNull final Collection<String> memberDNs)
475  {
476    final ArrayList<Attribute> attrList = new ArrayList<>(1);
477    attrList.add(new Attribute("member",
478         DistinguishedNameMatchingRule.getInstance(), memberDNs));
479
480    return generateEntry("cn", name, parentDN,
481         new String[] { "top", "groupOfNames" }, attrList);
482  }
483
484
485
486  /**
487   * Generates a group entry with the provided information.  It will include
488   * the top and groupOfUniqueNames object classes and will use cn as the RDN
489   * attribute.
490   *
491   * @param  name       The name for the group, which will be used as the value
492   *                    of the "cn" attribute.  It must not be {@code null}.
493   * @param  parentDN   The DN of the entry below which the new entry should be
494   *                    placed.  It may be {@code null} if the new entry should
495   *                    not have a parent.
496   * @param  memberDNs  The DNs of the users that should be listed as members of
497   *                    the group.
498   *
499   * @return  The generated entry.
500   */
501  @NotNull()
502  public static Entry generateGroupOfUniqueNamesEntry(
503                           @NotNull final String name,
504                           @Nullable final String parentDN,
505                           @NotNull final String... memberDNs)
506  {
507    return generateGroupOfUniqueNamesEntry(name, parentDN,
508         StaticUtils.toList(memberDNs));
509  }
510
511
512
513  /**
514   * Generates a group entry with the provided information.  It will include
515   * the top and groupOfUniqueNames object classes and will use cn as the RDN
516   * attribute.
517   *
518   * @param  name       The name for the group, which will be used as the value
519   *                    of the "cn" attribute.  It must not be {@code null}.
520   * @param  parentDN   The DN of the entry below which the new entry should be
521   *                    placed.  It may be {@code null} if the new entry should
522   *                    not have a parent.
523   * @param  memberDNs  The DNs of the users that should be listed as members of
524   *                    the group.
525   *
526   * @return  The generated entry.
527   */
528  @NotNull()
529  public static Entry generateGroupOfUniqueNamesEntry(
530                           @NotNull final String name,
531                           @Nullable final String parentDN,
532                           @NotNull final Collection<String> memberDNs)
533  {
534    final ArrayList<Attribute> attrList = new ArrayList<>(1);
535    attrList.add(new Attribute("uniqueMember",
536         DistinguishedNameMatchingRule.getInstance(), memberDNs));
537
538    return generateEntry("cn", name, parentDN,
539         new String[] { "top", "groupOfUniqueNames" }, attrList);
540  }
541
542
543
544  /**
545   * Generates entry with the provided information.
546   *
547   * @param  rdnAttr               The name of the attribute to use for the RDN.
548   * @param  rdnValue              The value of the attribute to use for the
549   *                               RDN.
550   * @param  parentDN              The DN of the entry below which the new
551   *                               entry should be placed.  It may be
552   *                               {@code null} if the new entry should not have
553   *                               a parent.
554   * @param  objectClasses         The object class values to include in the
555   *                               entry.
556   * @param  additionalAttributes  A set of additional attributes to include in
557   *                               the generated entry.  It may be {@code null}
558   *                               or empty if no additional attributes should
559   *                               be included.
560   *
561   * @return  The generated entry.
562   */
563  @NotNull()
564  private static Entry generateEntry(@NotNull final String rdnAttr,
565               @NotNull final String rdnValue,
566               @Nullable final String parentDN,
567               @NotNull final String[] objectClasses,
568               @Nullable final Collection<Attribute> additionalAttributes)
569  {
570    final RDN rdn = new RDN(rdnAttr, rdnValue);
571
572    final String dn;
573    if ((parentDN == null) || parentDN.trim().isEmpty())
574    {
575      dn = rdn.toString();
576    }
577    else
578    {
579      dn = rdn.toString() + ',' + parentDN;
580    }
581
582    final Entry entry = new Entry(dn,
583         new Attribute("objectClass", objectClasses),
584         new Attribute(rdnAttr, rdnValue));
585
586    if (additionalAttributes != null)
587    {
588      for (final Attribute a : additionalAttributes)
589      {
590        entry.addAttribute(a);
591      }
592    }
593
594    return entry;
595  }
596
597
598
599  /**
600   * Indicates whether the specified entry exists in the server.
601   *
602   * @param  conn  The connection to use to communicate with the directory
603   *               server.
604   * @param  dn    The DN of the entry for which to make the determination.
605   *
606   * @return  {@code true} if the entry exists, or {@code false} if not.
607   *
608   * @throws  LDAPException  If a problem is encountered while trying to
609   *                         communicate with the directory server.
610   */
611  public static boolean entryExists(@NotNull final LDAPInterface conn,
612                                    @NotNull final String dn)
613         throws LDAPException
614  {
615    return (conn.getEntry(dn, "1.1") != null);
616  }
617
618
619
620  /**
621   * Indicates whether the specified entry exists in the server and matches the
622   * given filter.
623   *
624   * @param  conn    The connection to use to communicate with the directory
625   *                 server.
626   * @param  dn      The DN of the entry for which to make the determination.
627   * @param  filter  The filter the entry is expected to match.
628   *
629   * @return  {@code true} if the entry exists and matches the specified filter,
630   *          or {@code false} if not.
631   *
632   * @throws  LDAPException  If a problem is encountered while trying to
633   *                         communicate with the directory server.
634   */
635  public static boolean entryExists(@NotNull final LDAPInterface conn,
636                                    @NotNull final String dn,
637                                    @NotNull final String filter)
638         throws LDAPException
639  {
640    try
641    {
642      final SearchResult searchResult =
643           conn.search(dn, SearchScope.BASE, filter, "1.1");
644      return (searchResult.getEntryCount() == 1);
645    }
646    catch (final LDAPException le)
647    {
648      if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
649      {
650        return false;
651      }
652      else
653      {
654        throw le;
655      }
656    }
657  }
658
659
660
661  /**
662   * Indicates whether the specified entry exists in the server.  This will
663   * return {@code true} only if the target entry exists and contains all values
664   * for all attributes of the provided entry.  The entry will be allowed to
665   * have attribute values not included in the provided entry.
666   *
667   * @param  conn   The connection to use to communicate with the directory
668   *                server.
669   * @param  entry  The entry to compare against the directory server.
670   *
671   * @return  {@code true} if the entry exists in the server and is a superset
672   *          of the provided entry, or {@code false} if not.
673   *
674   * @throws  LDAPException  If a problem is encountered while trying to
675   *                         communicate with the directory server.
676   */
677  public static boolean entryExists(@NotNull final LDAPInterface conn,
678                                    @NotNull final Entry entry)
679         throws LDAPException
680  {
681    final Collection<Attribute> attrs = entry.getAttributes();
682
683    final List<Filter> comps = new ArrayList<>(attrs.size());
684    for (final Attribute a : attrs)
685    {
686      for (final byte[] value : a.getValueByteArrays())
687      {
688        comps.add(Filter.createEqualityFilter(a.getName(), value));
689      }
690    }
691
692    try
693    {
694      final SearchResult searchResult = conn.search(entry.getDN(),
695           SearchScope.BASE, Filter.createANDFilter(comps), "1.1");
696      return (searchResult.getEntryCount() == 1);
697    }
698    catch (final LDAPException le)
699    {
700      if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
701      {
702        return false;
703      }
704      else
705      {
706        throw le;
707      }
708    }
709  }
710
711
712
713  /**
714   * Ensures that an entry with the provided DN exists in the directory.
715   *
716   * @param  conn  The connection to use to communicate with the directory
717   *               server.
718   * @param  dn    The DN of the entry for which to make the determination.
719   *
720   * @throws  LDAPException  If a problem is encountered while trying to
721   *                         communicate with the directory server.
722   *
723   * @throws  AssertionError  If the target entry does not exist.
724   */
725  public static void assertEntryExists(@NotNull final LDAPInterface conn,
726                                       @NotNull final String dn)
727         throws LDAPException, AssertionError
728  {
729    if (conn.getEntry(dn, "1.1") == null)
730    {
731      throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
732    }
733  }
734
735
736
737  /**
738   * Ensures that an entry with the provided DN exists in the directory.
739   *
740   * @param  conn    The connection to use to communicate with the directory
741   *                 server.
742   * @param  dn      The DN of the entry for which to make the determination.
743   * @param  filter  A filter that the target entry must match.
744   *
745   * @throws  LDAPException  If a problem is encountered while trying to
746   *                         communicate with the directory server.
747   *
748   * @throws  AssertionError  If the target entry does not exist or does not
749   *                          match the provided filter.
750   */
751  public static void assertEntryExists(@NotNull final LDAPInterface conn,
752                                       @NotNull final String dn,
753                                       @NotNull final String filter)
754         throws LDAPException, AssertionError
755  {
756    try
757    {
758      final SearchResult searchResult =
759           conn.search(dn, SearchScope.BASE, filter, "1.1");
760      if (searchResult.getEntryCount() == 0)
761      {
762        throw new AssertionError(ERR_TEST_ENTRY_DOES_NOT_MATCH_FILTER.get(dn,
763             filter));
764      }
765    }
766    catch (final LDAPException le)
767    {
768      if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
769      {
770        throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
771      }
772      else
773      {
774        throw le;
775      }
776    }
777  }
778
779
780
781  /**
782   * Ensures that an entry exists in the directory with the same DN and all
783   * attribute values contained in the provided entry.  The server entry may
784   * contain additional attributes and/or attribute values not included in the
785   * provided entry.
786   *
787   * @param  conn   The connection to use to communicate with the directory
788   *                server.
789   * @param  entry  The entry expected to be present in the directory server.
790   *
791   * @throws  LDAPException  If a problem is encountered while trying to
792   *                         communicate with the directory server.
793   *
794   * @throws  AssertionError  If the target entry does not exist or does not
795   *                          match the provided filter.
796   */
797  public static void assertEntryExists(@NotNull final LDAPInterface conn,
798                                       @NotNull final Entry entry)
799         throws LDAPException, AssertionError
800  {
801    // First, try to make the determination with a single search.  Only if
802    // this returns false will we perform a more thorough test to construct the
803    // most useful error message possible.
804    if (entryExists(conn, entry))
805    {
806      return;
807    }
808
809    final Collection<Attribute> attributes = entry.getAttributes();
810    final List<String> messages = new ArrayList<>(attributes.size());
811
812    for (final Attribute a : attributes)
813    {
814      // Determine whether the attribute is present in the entry.
815      try
816      {
817        final SearchResult searchResult = conn.search(entry.getDN(),
818             SearchScope.BASE, Filter.createPresenceFilter(a.getName()), "1.1");
819        if (searchResult.getEntryCount() == 0)
820        {
821          messages.add(ERR_TEST_ATTR_MISSING.get(entry.getDN(), a.getName()));
822          continue;
823        }
824      }
825      catch (final LDAPException le)
826      {
827        if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
828        {
829          throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(entry.getDN()));
830        }
831        else
832        {
833          throw le;
834        }
835      }
836
837      for (final byte[] value : a.getValueByteArrays())
838      {
839        final SearchResult searchResult = conn.search(entry.getDN(),
840             SearchScope.BASE, Filter.createEqualityFilter(a.getName(), value),
841             "1.1");
842        if (searchResult.getEntryCount() == 0)
843        {
844          messages.add(ERR_TEST_VALUE_MISSING.get(entry.getDN(), a.getName(),
845               StaticUtils.toUTF8String(value)));
846        }
847      }
848    }
849
850    if (! messages.isEmpty())
851    {
852      throw new AssertionError(StaticUtils.concatenateStrings(messages));
853    }
854  }
855
856
857
858  /**
859   * Retrieves a list containing the DNs of the entries which are missing from
860   * the directory server.
861   *
862   * @param  conn  The connection to use to communicate with the directory
863   *               server.
864   * @param  dns   The DNs of the entries to try to find in the server.
865   *
866   * @return  A list containing all of the provided DNs that were not found in
867   *          the server, or an empty list if all entries were found.
868   *
869   * @throws  LDAPException  If a problem is encountered while trying to
870   *                         communicate with the directory server.
871   */
872  @NotNull()
873  public static List<String> getMissingEntryDNs(
874                                  @NotNull final LDAPInterface conn,
875                                  @NotNull final String... dns)
876         throws LDAPException
877  {
878    return getMissingEntryDNs(conn, StaticUtils.toList(dns));
879  }
880
881
882
883  /**
884   * Retrieves a list containing the DNs of the entries which are missing from
885   * the directory server.
886   *
887   * @param  conn  The connection to use to communicate with the directory
888   *               server.
889   * @param  dns   The DNs of the entries to try to find in the server.
890   *
891   * @return  A list containing all of the provided DNs that were not found in
892   *          the server, or an empty list if all entries were found.
893   *
894   * @throws  LDAPException  If a problem is encountered while trying to
895   *                         communicate with the directory server.
896   */
897  @NotNull()
898  public static List<String> getMissingEntryDNs(
899                                  @NotNull final LDAPInterface conn,
900                                  @NotNull final Collection<String> dns)
901         throws LDAPException
902  {
903    final List<String> missingDNs = new ArrayList<>(dns.size());
904
905    for (final String dn : dns)
906    {
907      if (conn.getEntry(dn, "1.1") == null)
908      {
909        missingDNs.add(dn);
910      }
911    }
912
913    return missingDNs;
914  }
915
916
917
918  /**
919   * Ensures that all of the entries with the provided DNs exist in the
920   * directory.
921   *
922   * @param  conn  The connection to use to communicate with the directory
923   *               server.
924   * @param  dns   The DNs of the entries for which to make the determination.
925   *
926   * @throws  LDAPException  If a problem is encountered while trying to
927   *                         communicate with the directory server.
928   *
929   * @throws  AssertionError  If any of the target entries does not exist.
930   */
931  public static void assertEntriesExist(@NotNull final LDAPInterface conn,
932                                        @NotNull final String... dns)
933         throws LDAPException, AssertionError
934  {
935    assertEntriesExist(conn, StaticUtils.toList(dns));
936  }
937
938
939
940  /**
941   * Ensures that all of the entries with the provided DNs exist in the
942   * directory.
943   *
944   * @param  conn  The connection to use to communicate with the directory
945   *               server.
946   * @param  dns   The DNs of the entries for which to make the determination.
947   *
948   * @throws  LDAPException  If a problem is encountered while trying to
949   *                         communicate with the directory server.
950   *
951   * @throws  AssertionError  If any of the target entries does not exist.
952   */
953  public static void assertEntriesExist(@NotNull final LDAPInterface conn,
954                                        @NotNull final Collection<String> dns)
955         throws LDAPException, AssertionError
956  {
957    final List<String> missingDNs = getMissingEntryDNs(conn, dns);
958    if (missingDNs.isEmpty())
959    {
960      return;
961    }
962
963    final ArrayList<String> msgList = new ArrayList<>(missingDNs.size());
964    for (final String dn : missingDNs)
965    {
966      msgList.add(ERR_TEST_ENTRY_MISSING.get(dn));
967    }
968
969    throw new AssertionError(StaticUtils.concatenateStrings(msgList));
970  }
971
972
973
974  /**
975   * Retrieves a list containing all of the named attributes which do not exist
976   * in the target entry.
977   *
978   * @param  conn            The connection to use to communicate with the
979   *                         directory server.
980   * @param  dn              The DN of the entry to examine.
981   * @param  attributeNames  The names of the attributes expected to be present
982   *                         in the target entry.
983   *
984   * @return  A list containing the names of the attributes which were not
985   *          present in the target entry, an empty list if all specified
986   *          attributes were found in the entry, or {@code null} if the target
987   *          entry does not exist.
988   *
989   * @throws  LDAPException  If a problem is encountered while trying to
990   *                         communicate with the directory server.
991   */
992  @Nullable()
993  public static List<String> getMissingAttributeNames(
994                                  @NotNull final LDAPInterface conn,
995                                  @NotNull final String dn,
996                                  @NotNull final String... attributeNames)
997         throws LDAPException
998  {
999    return getMissingAttributeNames(conn, dn,
1000         StaticUtils.toList(attributeNames));
1001  }
1002
1003
1004
1005  /**
1006   * Retrieves a list containing all of the named attributes which do not exist
1007   * in the target entry.
1008   *
1009   * @param  conn            The connection to use to communicate with the
1010   *                         directory server.
1011   * @param  dn              The DN of the entry to examine.
1012   * @param  attributeNames  The names of the attributes expected to be present
1013   *                         in the target entry.
1014   *
1015   * @return  A list containing the names of the attributes which were not
1016   *          present in the target entry, an empty list if all specified
1017   *          attributes were found in the entry, or {@code null} if the target
1018   *          entry does not exist.
1019   *
1020   * @throws  LDAPException  If a problem is encountered while trying to
1021   *                         communicate with the directory server.
1022   */
1023  @Nullable()
1024  public static List<String> getMissingAttributeNames(
1025                     @NotNull final LDAPInterface conn,
1026                     @NotNull final String dn,
1027                     @NotNull final Collection<String> attributeNames)
1028         throws LDAPException
1029  {
1030    final List<String> missingAttrs = new ArrayList<>(attributeNames.size());
1031
1032    // We will use a separate search for each target attribute so that we can
1033    // handle the case in which the attribute is present with a different name
1034    // than the one provided.
1035    for (final String attrName : attributeNames)
1036    {
1037      try
1038      {
1039        final SearchResult result = conn.search(dn, SearchScope.BASE,
1040             Filter.createPresenceFilter(attrName));
1041        if (result.getEntryCount() == 0)
1042        {
1043          missingAttrs.add(attrName);
1044        }
1045      }
1046      catch (final LDAPException le)
1047      {
1048        if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
1049        {
1050          return null;
1051        }
1052        else
1053        {
1054          throw le;
1055        }
1056      }
1057    }
1058
1059    return missingAttrs;
1060  }
1061
1062
1063
1064  /**
1065   * Ensures that the specified entry exists in the directory with all of the
1066   * specified attributes.
1067   *
1068   * @param  conn            The connection to use to communicate with the
1069   *                         directory server.
1070   * @param  dn              The DN of the entry to examine.
1071   * @param  attributeNames  The names of the attributes that are expected to be
1072   *                         present in the provided entry.
1073   *
1074   * @throws  LDAPException  If a problem is encountered while trying to
1075   *                         communicate with the directory server.
1076   *
1077   * @throws  AssertionError  If the target entry does not exist or does not
1078   *                          contain all of the specified attributes.
1079   */
1080  public static void assertAttributeExists(
1081                          @NotNull final LDAPInterface conn,
1082                          @NotNull final String dn,
1083                          @NotNull final String... attributeNames)
1084        throws LDAPException, AssertionError
1085  {
1086    assertAttributeExists(conn, dn, StaticUtils.toList(attributeNames));
1087  }
1088
1089
1090
1091  /**
1092   * Ensures that the specified entry exists in the directory with all of the
1093   * specified attributes.
1094   *
1095   * @param  conn            The connection to use to communicate with the
1096   *                         directory server.
1097   * @param  dn              The DN of the entry to examine.
1098   * @param  attributeNames  The names of the attributes that are expected to be
1099   *                         present in the provided entry.
1100   *
1101   * @throws  LDAPException  If a problem is encountered while trying to
1102   *                         communicate with the directory server.
1103   *
1104   * @throws  AssertionError  If the target entry does not exist or does not
1105   *                          contain all of the specified attributes.
1106   */
1107  public static void assertAttributeExists(@NotNull final LDAPInterface conn,
1108                          @NotNull final String dn,
1109                          @NotNull final Collection<String> attributeNames)
1110        throws LDAPException, AssertionError
1111  {
1112    final List<String> missingAttrs =
1113         getMissingAttributeNames(conn, dn, attributeNames);
1114    if (missingAttrs == null)
1115    {
1116      // The target entry does not exist.
1117      throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
1118    }
1119    else if (missingAttrs.isEmpty())
1120    {
1121      return;
1122    }
1123
1124    final List<String> msgList = new ArrayList<>(missingAttrs.size());
1125    for (final String attrName : missingAttrs)
1126    {
1127      msgList.add(ERR_TEST_ATTR_MISSING.get(dn, attrName));
1128    }
1129
1130    throw new AssertionError(StaticUtils.concatenateStrings(msgList));
1131  }
1132
1133
1134
1135  /**
1136   * Retrieves a list of all provided attribute values which are missing from
1137   * the specified entry.
1138   *
1139   * @param  conn             The connection to use to communicate with the
1140   *                          directory server.
1141   * @param  dn               The DN of the entry to examine.
1142   * @param  attributeName    The attribute expected to be present in the target
1143   *                          entry with the given values.
1144   * @param  attributeValues  The values expected to be present in the target
1145   *                          entry.
1146   *
1147   * @return  A list containing all of the provided values which were not found
1148   *          in the entry, an empty list if all provided attribute values were
1149   *          found, or {@code null} if the target entry does not exist.
1150   *
1151   * @throws  LDAPException  If a problem is encountered while trying to
1152   *                         communicate with the directory server.
1153   */
1154  @Nullable()
1155  public static List<String> getMissingAttributeValues(
1156                                  @NotNull final LDAPInterface conn,
1157                                  @NotNull final String dn,
1158                                  @NotNull final String attributeName,
1159                                  @NotNull final String... attributeValues)
1160         throws LDAPException
1161  {
1162    return getMissingAttributeValues(conn, dn, attributeName,
1163         StaticUtils.toList(attributeValues));
1164  }
1165
1166
1167
1168  /**
1169   * Retrieves a list of all provided attribute values which are missing from
1170   * the specified entry.  The target attribute may or may not contain
1171   * additional values.
1172   *
1173   * @param  conn             The connection to use to communicate with the
1174   *                          directory server.
1175   * @param  dn               The DN of the entry to examine.
1176   * @param  attributeName    The attribute expected to be present in the target
1177   *                          entry with the given values.
1178   * @param  attributeValues  The values expected to be present in the target
1179   *                          entry.
1180   *
1181   * @return  A list containing all of the provided values which were not found
1182   *          in the entry, an empty list if all provided attribute values were
1183   *          found, or {@code null} if the target entry does not exist.
1184   *
1185   * @throws  LDAPException  If a problem is encountered while trying to
1186   *                         communicate with the directory server.
1187   */
1188  @Nullable()
1189  public static List<String> getMissingAttributeValues(
1190                     @NotNull final LDAPInterface conn,
1191                     @NotNull final String dn,
1192                     @NotNull final String attributeName,
1193                     @NotNull final Collection<String> attributeValues)
1194       throws LDAPException
1195  {
1196    final List<String> missingValues = new ArrayList<>(attributeValues.size());
1197
1198    for (final String value : attributeValues)
1199    {
1200      try
1201      {
1202        final SearchResult searchResult = conn.search(dn, SearchScope.BASE,
1203             Filter.createEqualityFilter(attributeName, value), "1.1");
1204        if (searchResult.getEntryCount() == 0)
1205        {
1206          missingValues.add(value);
1207        }
1208      }
1209      catch (final LDAPException le)
1210      {
1211        if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
1212        {
1213          return null;
1214        }
1215        else
1216        {
1217          throw le;
1218        }
1219      }
1220    }
1221
1222    return missingValues;
1223  }
1224
1225
1226
1227  /**
1228   * Ensures that the specified entry exists in the directory with all of the
1229   * specified values for the given attribute.  The attribute may or may not
1230   * contain additional values.
1231   *
1232   * @param  conn             The connection to use to communicate with the
1233   *                          directory server.
1234   * @param  dn               The DN of the entry to examine.
1235   * @param  attributeName    The name of the attribute to examine.
1236   * @param  attributeValues  The set of values which must exist for the given
1237   *                          attribute.
1238   *
1239   * @throws  LDAPException  If a problem is encountered while trying to
1240   *                         communicate with the directory server.
1241   *
1242   * @throws  AssertionError  If the target entry does not exist, does not
1243   *                          contain the specified attribute, or that attribute
1244   *                          does not have all of the specified values.
1245   */
1246  public static void assertValueExists(@NotNull final LDAPInterface conn,
1247                                       @NotNull final String dn,
1248                                       @NotNull final String attributeName,
1249                                       @NotNull final String... attributeValues)
1250        throws LDAPException, AssertionError
1251  {
1252    assertValueExists(conn, dn, attributeName,
1253         StaticUtils.toList(attributeValues));
1254  }
1255
1256
1257
1258  /**
1259   * Ensures that the specified entry exists in the directory with all of the
1260   * specified values for the given attribute.  The attribute may or may not
1261   * contain additional values.
1262   *
1263   * @param  conn             The connection to use to communicate with the
1264   *                          directory server.
1265   * @param  dn               The DN of the entry to examine.
1266   * @param  attributeName    The name of the attribute to examine.
1267   * @param  attributeValues  The set of values which must exist for the given
1268   *                          attribute.
1269   *
1270   * @throws  LDAPException  If a problem is encountered while trying to
1271   *                         communicate with the directory server.
1272   *
1273   * @throws  AssertionError  If the target entry does not exist, does not
1274   *                          contain the specified attribute, or that attribute
1275   *                          does not have all of the specified values.
1276   */
1277  public static void assertValueExists(@NotNull final LDAPInterface conn,
1278                          @NotNull final String dn,
1279                          @NotNull final String attributeName,
1280                          @NotNull final Collection<String> attributeValues)
1281        throws LDAPException, AssertionError
1282  {
1283    final List<String> missingValues =
1284         getMissingAttributeValues(conn, dn, attributeName, attributeValues);
1285    if (missingValues == null)
1286    {
1287      // The target entry does not exist.
1288      throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
1289    }
1290    else if (missingValues.isEmpty())
1291    {
1292      return;
1293    }
1294
1295    // Get the entry and see if the attribute exists in it at all.
1296    final Entry entry = conn.getEntry(dn, attributeName);
1297    if ((entry != null) && entry.hasAttribute(attributeName))
1298    {
1299      final Attribute a = entry.getAttribute(attributeName);
1300      throw new AssertionError(ERR_TEST_ATTR_MISSING_VALUE.get(dn,
1301           attributeName,
1302           StaticUtils.concatenateStrings("{", " '", ",", "'", " }",
1303                a.getValues()),
1304           StaticUtils.concatenateStrings("{", " '", ",", "'", " }",
1305                missingValues)));
1306    }
1307    else
1308    {
1309      throw new AssertionError(ERR_TEST_ATTR_MISSING.get(dn, attributeName));
1310    }
1311  }
1312
1313
1314
1315  /**
1316   * Ensures that the specified entry does not exist in the directory.
1317   *
1318   * @param  conn  The connection to use to communicate with the directory
1319   *               server.
1320   * @param  dn    The DN of the entry expected to be missing.
1321   *
1322   * @throws  LDAPException  If a problem is encountered while trying to
1323   *                         communicate with the directory server.
1324   *
1325   * @throws  AssertionError  If the target entry is found in the server.
1326   */
1327  public static void assertEntryMissing(@NotNull final LDAPInterface conn,
1328                                        @NotNull final String dn)
1329         throws LDAPException, AssertionError
1330  {
1331    if (conn.getEntry(dn, "1.1") != null)
1332    {
1333      throw new AssertionError(ERR_TEST_ENTRY_EXISTS.get(dn));
1334    }
1335  }
1336
1337
1338
1339  /**
1340   * Ensures that the specified entry exists in the directory but does not
1341   * contain any of the specified attributes.
1342   *
1343   * @param  conn            The connection to use to communicate with the
1344   *                         directory server.
1345   * @param  dn              The DN of the entry expected to be present.
1346   * @param  attributeNames  The names of the attributes expected to be missing
1347   *                         from the entry.
1348   *
1349   * @throws  LDAPException  If a problem is encountered while trying to
1350   *                         communicate with the directory server.
1351   *
1352   * @throws  AssertionError  If the target entry is missing from the server, or
1353   *                          if it contains any of the target attributes.
1354   */
1355  public static void assertAttributeMissing(@NotNull final LDAPInterface conn,
1356                          @NotNull final String dn,
1357                          @NotNull final String... attributeNames)
1358         throws LDAPException, AssertionError
1359  {
1360    assertAttributeMissing(conn, dn, StaticUtils.toList(attributeNames));
1361  }
1362
1363
1364
1365  /**
1366   * Ensures that the specified entry exists in the directory but does not
1367   * contain any of the specified attributes.
1368   *
1369   * @param  conn            The connection to use to communicate with the
1370   *                         directory server.
1371   * @param  dn              The DN of the entry expected to be present.
1372   * @param  attributeNames  The names of the attributes expected to be missing
1373   *                         from the entry.
1374   *
1375   * @throws  LDAPException  If a problem is encountered while trying to
1376   *                         communicate with the directory server.
1377   *
1378   * @throws  AssertionError  If the target entry is missing from the server, or
1379   *                          if it contains any of the target attributes.
1380   */
1381  public static void assertAttributeMissing(@NotNull final LDAPInterface conn,
1382                          @NotNull final String dn,
1383                          @NotNull final Collection<String> attributeNames)
1384         throws LDAPException, AssertionError
1385  {
1386    final List<String> messages = new ArrayList<>(attributeNames.size());
1387    for (final String attrName : attributeNames)
1388    {
1389      try
1390      {
1391        final SearchResult searchResult = conn.search(dn, SearchScope.BASE,
1392             Filter.createPresenceFilter(attrName), attrName);
1393        if (searchResult.getEntryCount() == 1)
1394        {
1395          final Attribute a =
1396               searchResult.getSearchEntries().get(0).getAttribute(attrName);
1397          if (a == null)
1398          {
1399            messages.add(ERR_TEST_ATTR_EXISTS.get(dn, attrName));
1400          }
1401          else
1402          {
1403            messages.add(ERR_TEST_ATTR_EXISTS_WITH_VALUES.get(dn, attrName,
1404                 StaticUtils.concatenateStrings("{", " '", ",", "'", " }",
1405                                 a.getValues())));
1406          }
1407        }
1408      }
1409      catch (final LDAPException le)
1410      {
1411        if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
1412        {
1413          throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
1414        }
1415        else
1416        {
1417          throw le;
1418        }
1419      }
1420    }
1421
1422    if (! messages.isEmpty())
1423    {
1424      throw new AssertionError(StaticUtils.concatenateStrings(messages));
1425    }
1426  }
1427
1428
1429
1430  /**
1431   * Ensures that the specified entry exists in the directory but does not
1432   * contain any of the specified attribute values.
1433   *
1434   * @param  conn             The connection to use to communicate with the
1435   *                          directory server.
1436   * @param  dn               The DN of the entry expected to be present.
1437   * @param  attributeName    The name of the attribute to examine.
1438   * @param  attributeValues  The values expected to be missing from the target
1439   *                          entry.
1440   *
1441   * @throws  LDAPException  If a problem is encountered while trying to
1442   *                         communicate with the directory server.
1443   *
1444   * @throws  AssertionError  If the target entry is missing from the server, or
1445   *                          if it contains any of the target attribute values.
1446   */
1447  public static void assertValueMissing(@NotNull final LDAPInterface conn,
1448                          @NotNull final String dn,
1449                          @NotNull final String attributeName,
1450                          @NotNull final String... attributeValues)
1451         throws LDAPException, AssertionError
1452  {
1453    assertValueMissing(conn, dn, attributeName,
1454         StaticUtils.toList(attributeValues));
1455  }
1456
1457
1458
1459  /**
1460   * Ensures that the specified entry exists in the directory but does not
1461   * contain any of the specified attribute values.
1462   *
1463   * @param  conn             The connection to use to communicate with the
1464   *                          directory server.
1465   * @param  dn               The DN of the entry expected to be present.
1466   * @param  attributeName    The name of the attribute to examine.
1467   * @param  attributeValues  The values expected to be missing from the target
1468   *                          entry.
1469   *
1470   * @throws  LDAPException  If a problem is encountered while trying to
1471   *                         communicate with the directory server.
1472   *
1473   * @throws  AssertionError  If the target entry is missing from the server, or
1474   *                          if it contains any of the target attribute values.
1475   */
1476  public static void assertValueMissing(@NotNull final LDAPInterface conn,
1477                          @NotNull final String dn,
1478                          @NotNull final String attributeName,
1479                          @NotNull final Collection<String> attributeValues)
1480         throws LDAPException, AssertionError
1481  {
1482    final List<String> messages = new ArrayList<>(attributeValues.size());
1483    for (final String value : attributeValues)
1484    {
1485      try
1486      {
1487        final SearchResult searchResult = conn.search(dn, SearchScope.BASE,
1488             Filter.createEqualityFilter(attributeName, value), "1.1");
1489        if (searchResult.getEntryCount() == 1)
1490        {
1491          messages.add(ERR_TEST_VALUE_EXISTS.get(dn, attributeName, value));
1492        }
1493      }
1494      catch (final LDAPException le)
1495      {
1496        if (le.getResultCode() == ResultCode.NO_SUCH_OBJECT)
1497        {
1498          throw new AssertionError(ERR_TEST_ENTRY_MISSING.get(dn));
1499        }
1500        else
1501        {
1502          throw le;
1503        }
1504      }
1505    }
1506
1507    if (! messages.isEmpty())
1508    {
1509      throw new AssertionError(StaticUtils.concatenateStrings(messages));
1510    }
1511  }
1512
1513
1514
1515  /**
1516   * Ensures that the result code for the provided result matches one of the
1517   * given acceptable result codes.
1518   *
1519   * @param  result                 The LDAP result to examine.
1520   * @param  acceptableResultCodes  The set of result codes that are considered
1521   *                                acceptable.
1522   *
1523   * @throws  AssertionError  If the result code from the provided result did
1524   *                          not match any of the acceptable values.
1525   */
1526  public static void assertResultCodeEquals(@NotNull final LDAPResult result,
1527                          @NotNull final ResultCode... acceptableResultCodes)
1528         throws AssertionError
1529  {
1530    for (final ResultCode rc : acceptableResultCodes)
1531    {
1532      if (rc.equals(result.getResultCode()))
1533      {
1534        return;
1535      }
1536    }
1537
1538    if (acceptableResultCodes.length == 1)
1539    {
1540      throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_MISSING.get(
1541           String.valueOf(result), String.valueOf(acceptableResultCodes[0])));
1542    }
1543    else
1544    {
1545      throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_MISSING.get(
1546           String.valueOf(result), Arrays.toString(acceptableResultCodes)));
1547    }
1548  }
1549
1550
1551
1552  /**
1553   * Ensures that the result code for the provided LDAP exception matches one of
1554   * the given acceptable result codes.
1555   *
1556   * @param  exception              The LDAP exception to examine.
1557   * @param  acceptableResultCodes  The set of result codes that are considered
1558   *                                acceptable.
1559   *
1560   * @throws  AssertionError  If the result code from the provided exception did
1561   *                          not match any of the acceptable values.
1562   */
1563  public static void assertResultCodeEquals(
1564                          @NotNull final LDAPException exception,
1565                          @NotNull final ResultCode... acceptableResultCodes)
1566         throws AssertionError
1567  {
1568    for (final ResultCode rc : acceptableResultCodes)
1569    {
1570      if (rc.equals(exception.getResultCode()))
1571      {
1572        return;
1573      }
1574    }
1575
1576    if (acceptableResultCodes.length == 1)
1577    {
1578      throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_MISSING.get(
1579           StaticUtils.getExceptionMessage(exception),
1580           String.valueOf(acceptableResultCodes[0])));
1581    }
1582    else
1583    {
1584      throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_MISSING.get(
1585           StaticUtils.getExceptionMessage(exception),
1586           Arrays.toString(acceptableResultCodes)));
1587    }
1588  }
1589
1590
1591
1592  /**
1593   * Processes the provided request using the given connection and ensures that
1594   * the result code matches one of the provided acceptable values.
1595   *
1596   * @param  conn                   The connection to use to communicate with
1597   *                                the directory server.
1598   * @param  request                The request to be processed.
1599   * @param  acceptableResultCodes  The set of result codes that are considered
1600   *                                acceptable.
1601   *
1602   * @return  The result returned from processing the requested operation.
1603   *
1604   * @throws  AssertionError  If the result code returned by the server did not
1605   *                          match any acceptable values.
1606   */
1607  @NotNull()
1608  public static LDAPResult assertResultCodeEquals(
1609                     @NotNull final LDAPConnection conn,
1610                     @NotNull final LDAPRequest request,
1611                     @NotNull final ResultCode... acceptableResultCodes)
1612         throws AssertionError
1613  {
1614    LDAPResult result;
1615
1616    try
1617    {
1618      result = conn.processOperation(request);
1619    }
1620    catch (final LDAPException le)
1621    {
1622      result = le.toLDAPResult();
1623    }
1624
1625    for (final ResultCode rc : acceptableResultCodes)
1626    {
1627      if (rc.equals(result.getResultCode()))
1628      {
1629        return result;
1630      }
1631    }
1632
1633    if (acceptableResultCodes.length == 1)
1634    {
1635      throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_MISSING.get(
1636           String.valueOf(result), String.valueOf(acceptableResultCodes[0])));
1637    }
1638    else
1639    {
1640      throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_MISSING.get(
1641           String.valueOf(result), Arrays.toString(acceptableResultCodes)));
1642    }
1643  }
1644
1645
1646
1647  /**
1648   * Ensures that the result code for the provided result does not match any of
1649   * the given unacceptable result codes.
1650   *
1651   * @param  result                   The LDAP result to examine.
1652   * @param  unacceptableResultCodes  The set of result codes that are
1653   *                                  considered unacceptable.
1654   *
1655   * @throws  AssertionError  If the result code from the provided result
1656   *                          matched any of the unacceptable values.
1657   */
1658  public static void assertResultCodeNot(@NotNull final LDAPResult result,
1659                          @NotNull final ResultCode... unacceptableResultCodes)
1660         throws AssertionError
1661  {
1662    for (final ResultCode rc : unacceptableResultCodes)
1663    {
1664      if (rc.equals(result.getResultCode()))
1665      {
1666        if (unacceptableResultCodes.length == 1)
1667        {
1668          throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_FOUND.get(
1669               String.valueOf(result),
1670               String.valueOf(unacceptableResultCodes[0])));
1671        }
1672        else
1673        {
1674          throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_FOUND.get(
1675               String.valueOf(result),
1676               Arrays.toString(unacceptableResultCodes)));
1677        }
1678      }
1679    }
1680  }
1681
1682
1683
1684  /**
1685   * Ensures that the result code for the provided result does not match any of
1686   * the given unacceptable result codes.
1687   *
1688   * @param  exception                The LDAP exception to examine.
1689   * @param  unacceptableResultCodes  The set of result codes that are
1690   *                                  considered unacceptable.
1691   *
1692   * @throws  AssertionError  If the result code from the provided result
1693   *                          matched any of the unacceptable values.
1694   */
1695  public static void assertResultCodeNot(@NotNull final LDAPException exception,
1696                          @NotNull final ResultCode... unacceptableResultCodes)
1697         throws AssertionError
1698  {
1699    for (final ResultCode rc : unacceptableResultCodes)
1700    {
1701      if (rc.equals(exception.getResultCode()))
1702      {
1703        if (unacceptableResultCodes.length == 1)
1704        {
1705          throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_FOUND.get(
1706               StaticUtils.getExceptionMessage(exception),
1707               String.valueOf(unacceptableResultCodes[0])));
1708        }
1709        else
1710        {
1711          throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_FOUND.get(
1712               StaticUtils.getExceptionMessage(exception),
1713               Arrays.toString(unacceptableResultCodes)));
1714        }
1715      }
1716    }
1717  }
1718
1719
1720
1721  /**
1722   * Processes the provided request using the given connection and ensures that
1723   * the result code does not match any of the given unacceptable values.
1724   *
1725   * @param  conn                     The connection to use to communicate with
1726   *                                  the directory server.
1727   * @param  request                  The request to be processed.
1728   * @param  unacceptableResultCodes  The set of result codes that are
1729   *                                  considered unacceptable.
1730   *
1731   * @return  The result returned from processing the requested operation.
1732   *
1733   * @throws  AssertionError  If the result code from the provided result
1734   *                          matched any of the unacceptable values.
1735   */
1736  @NotNull()
1737  public static LDAPResult assertResultCodeNot(
1738                     @NotNull final LDAPConnection conn,
1739                     @NotNull final LDAPRequest request,
1740                     @NotNull final ResultCode... unacceptableResultCodes)
1741         throws AssertionError
1742  {
1743    LDAPResult result;
1744
1745    try
1746    {
1747      result = conn.processOperation(request);
1748    }
1749    catch (final LDAPException le)
1750    {
1751      result = le.toLDAPResult();
1752    }
1753
1754    for (final ResultCode rc : unacceptableResultCodes)
1755    {
1756      if (rc.equals(result.getResultCode()))
1757      {
1758        if (unacceptableResultCodes.length == 1)
1759        {
1760          throw new AssertionError(ERR_TEST_SINGLE_RESULT_CODE_FOUND.get(
1761               String.valueOf(result),
1762               String.valueOf(unacceptableResultCodes[0])));
1763        }
1764        else
1765        {
1766          throw new AssertionError(ERR_TEST_MULTI_RESULT_CODE_FOUND.get(
1767               String.valueOf(result),
1768               Arrays.toString(unacceptableResultCodes)));
1769        }
1770      }
1771    }
1772
1773    return result;
1774  }
1775
1776
1777
1778  /**
1779   * Ensures that the provided LDAP result contains a matched DN value.
1780   *
1781   * @param  result  The LDAP result to examine.
1782   *
1783   * @throws  AssertionError  If the provided result did not contain a matched
1784   *                          DN value.
1785   */
1786  public static void assertContainsMatchedDN(@NotNull final LDAPResult result)
1787         throws AssertionError
1788  {
1789    if (result.getMatchedDN() == null)
1790    {
1791      throw new AssertionError(ERR_TEST_RESULT_MISSING_MATCHED_DN.get(
1792           String.valueOf(result)));
1793    }
1794  }
1795
1796
1797
1798  /**
1799   * Ensures that the provided LDAP exception contains a matched DN value.
1800   *
1801   * @param  exception  The LDAP exception to examine.
1802   *
1803   * @throws  AssertionError  If the provided exception did not contain a
1804   *                          matched DN value.
1805   */
1806  public static void assertContainsMatchedDN(
1807                          @NotNull final LDAPException exception)
1808         throws AssertionError
1809  {
1810    if (exception.getMatchedDN() == null)
1811    {
1812      throw new AssertionError(ERR_TEST_RESULT_MISSING_MATCHED_DN.get(
1813           StaticUtils.getExceptionMessage(exception)));
1814    }
1815  }
1816
1817
1818
1819  /**
1820   * Ensures that the provided LDAP result does not contain a matched DN value.
1821   *
1822   * @param  result  The LDAP result to examine.
1823   *
1824   * @throws  AssertionError  If the provided result contained a matched DN
1825   *                          value.
1826   */
1827  public static void assertMissingMatchedDN(@NotNull final LDAPResult result)
1828         throws AssertionError
1829  {
1830    if (result.getMatchedDN() != null)
1831    {
1832      throw new AssertionError(ERR_TEST_RESULT_CONTAINS_MATCHED_DN.get(
1833           String.valueOf(result), result.getMatchedDN()));
1834    }
1835  }
1836
1837
1838
1839  /**
1840   * Ensures that the provided LDAP exception does not contain a matched DN
1841   * value.
1842   *
1843   * @param  exception  The LDAP exception to examine.
1844   *
1845   * @throws  AssertionError  If the provided exception contained a matched DN
1846   *                          value.
1847   */
1848  public static void assertMissingMatchedDN(
1849                          @NotNull final LDAPException exception)
1850         throws AssertionError
1851  {
1852    if (exception.getMatchedDN() != null)
1853    {
1854      throw new AssertionError(ERR_TEST_RESULT_CONTAINS_MATCHED_DN.get(
1855           StaticUtils.getExceptionMessage(exception),
1856           exception.getMatchedDN()));
1857    }
1858  }
1859
1860
1861
1862  /**
1863   * Ensures that the provided LDAP result has the given matched DN value.
1864   *
1865   * @param  result     The LDAP result to examine.
1866   * @param  matchedDN  The matched DN value expected to be found in the
1867   *                    provided result.  It must not be {@code null}.
1868   *
1869   * @throws  LDAPException  If either the found or expected matched DN values
1870   *                         could not be parsed as a valid DN.
1871   *
1872   * @throws  AssertionError  If the provided LDAP result did not contain a
1873   *                          matched DN, or if it had a matched DN that
1874   *                          differed from the expected value.
1875   */
1876  public static void assertMatchedDNEquals(@NotNull final LDAPResult result,
1877                                           @NotNull final String matchedDN)
1878         throws LDAPException, AssertionError
1879  {
1880    if (result.getMatchedDN() == null)
1881    {
1882      throw new AssertionError(ERR_TEST_RESULT_MISSING_EXPECTED_MATCHED_DN.get(
1883           String.valueOf(result), matchedDN));
1884    }
1885
1886    final DN foundDN    = new DN(result.getMatchedDN());
1887    final DN expectedDN = new DN(matchedDN);
1888    if (! foundDN.equals(expectedDN))
1889    {
1890      throw new AssertionError(ERR_TEST_MATCHED_DN_MISMATCH.get(
1891           String.valueOf(result), matchedDN, result.getMatchedDN()));
1892    }
1893  }
1894
1895
1896
1897  /**
1898   * Ensures that the provided LDAP exception has the given matched DN value.
1899   *
1900   * @param  exception  The LDAP exception to examine.
1901   * @param  matchedDN  The matched DN value expected to be found in the
1902   *                    provided exception.  It must not be {@code null}.
1903   *
1904   * @throws  LDAPException  If either the found or expected matched DN values
1905   *                         could not be parsed as a valid DN.
1906   *
1907   * @throws  AssertionError  If the provided LDAP exception did not contain a
1908   *                          matched DN, or if it had a matched DN that
1909   *                          differed from the expected value.
1910   */
1911  public static void assertMatchedDNEquals(
1912                          @NotNull final LDAPException exception,
1913                          @NotNull final String matchedDN)
1914         throws LDAPException, AssertionError
1915  {
1916    if (exception.getMatchedDN() == null)
1917    {
1918      throw new AssertionError(ERR_TEST_RESULT_MISSING_EXPECTED_MATCHED_DN.get(
1919           StaticUtils.getExceptionMessage(exception), matchedDN));
1920    }
1921
1922    final DN foundDN    = new DN(exception.getMatchedDN());
1923    final DN expectedDN = new DN(matchedDN);
1924    if (! foundDN.equals(expectedDN))
1925    {
1926      throw new AssertionError(ERR_TEST_MATCHED_DN_MISMATCH.get(
1927           StaticUtils.getExceptionMessage(exception), matchedDN,
1928           exception.getMatchedDN()));
1929    }
1930  }
1931
1932
1933
1934  /**
1935   * Ensures that the provided LDAP result contains a diagnostic message.
1936   *
1937   * @param  result  The LDAP result to examine.
1938   *
1939   * @throws  AssertionError  If the provided result did not contain a
1940   *                          diagnostic message.
1941   */
1942  public static void assertContainsDiagnosticMessage(
1943                          @NotNull final LDAPResult result)
1944         throws AssertionError
1945  {
1946    if (result.getDiagnosticMessage() == null)
1947    {
1948      throw new AssertionError(ERR_TEST_RESULT_MISSING_DIAGNOSTIC_MESSAGE.get(
1949           String.valueOf(result)));
1950    }
1951  }
1952
1953
1954
1955  /**
1956   * Ensures that the provided LDAP exception contains a diagnostic message.
1957   *
1958   * @param  exception  The LDAP exception to examine.
1959   *
1960   * @throws  AssertionError  If the provided exception did not contain a
1961   *                          diagnostic message.
1962   */
1963  public static void assertContainsDiagnosticMessage(
1964                          @NotNull final LDAPException exception)
1965         throws AssertionError
1966  {
1967    if (exception.getDiagnosticMessage() == null)
1968    {
1969      throw new AssertionError(ERR_TEST_RESULT_MISSING_DIAGNOSTIC_MESSAGE.get(
1970           StaticUtils.getExceptionMessage(exception)));
1971    }
1972  }
1973
1974
1975
1976  /**
1977   * Ensures that the provided LDAP result does not contain a diagnostic
1978   * message.
1979   *
1980   * @param  result  The LDAP result to examine.
1981   *
1982   * @throws  AssertionError  If the provided result contained a diagnostic
1983   *                          message.
1984   */
1985  public static void assertMissingDiagnosticMessage(
1986                          @NotNull final LDAPResult result)
1987         throws AssertionError
1988  {
1989    if (result.getDiagnosticMessage() != null)
1990    {
1991      throw new AssertionError(ERR_TEST_RESULT_CONTAINS_DIAGNOSTIC_MESSAGE.get(
1992           String.valueOf(result), result.getDiagnosticMessage()));
1993    }
1994  }
1995
1996
1997
1998  /**
1999   * Ensures that the provided LDAP exception does not contain a diagnostic
2000   * message.
2001   *
2002   * @param  exception  The LDAP exception to examine.
2003   *
2004   * @throws  AssertionError  If the provided exception contained a diagnostic
2005   *                          message.
2006   */
2007  public static void assertMissingDiagnosticMessage(
2008                          @NotNull final LDAPException exception)
2009         throws AssertionError
2010  {
2011    if (exception.getDiagnosticMessage() != null)
2012    {
2013      throw new AssertionError(ERR_TEST_RESULT_CONTAINS_DIAGNOSTIC_MESSAGE.get(
2014           StaticUtils.getExceptionMessage(exception),
2015           exception.getDiagnosticMessage()));
2016    }
2017  }
2018
2019
2020
2021  /**
2022   * Ensures that the provided LDAP result has the given diagnostic message.
2023   *
2024   * @param  result             The LDAP result to examine.
2025   * @param  diagnosticMessage  The diagnostic message expected to be found in
2026   *                            the provided result.  It must not be
2027   *                            {@code null}.
2028   *
2029   * @throws  AssertionError  If the provided LDAP result did not contain a
2030   *                          diagnostic message, or if it had a diagnostic
2031   *                          message that differed from the expected value.
2032   */
2033  public static void assertDiagnosticMessageEquals(
2034                          @NotNull final LDAPResult result,
2035                          @NotNull final String diagnosticMessage)
2036         throws AssertionError
2037  {
2038    if (result.getDiagnosticMessage() == null)
2039    {
2040      throw new AssertionError(
2041           ERR_TEST_RESULT_MISSING_EXPECTED_DIAGNOSTIC_MESSAGE.get(
2042                String.valueOf(result), diagnosticMessage));
2043    }
2044
2045    if (! result.getDiagnosticMessage().equals(diagnosticMessage))
2046    {
2047      throw new AssertionError(ERR_TEST_DIAGNOSTIC_MESSAGE_MISMATCH.get(
2048           String.valueOf(result), diagnosticMessage,
2049           result.getDiagnosticMessage()));
2050    }
2051  }
2052
2053
2054
2055  /**
2056   * Ensures that the provided LDAP exception has the given diagnostic message.
2057   *
2058   * @param  exception          The LDAP exception to examine.
2059   * @param  diagnosticMessage  The diagnostic message expected to be found in
2060   *                            the provided exception.  It must not be
2061   *                            {@code null}.
2062   *
2063   * @throws  AssertionError  If the provided LDAP exception did not contain a
2064   *                          diagnostic message, or if it had a diagnostic
2065   *                          message that differed from the expected value.
2066   */
2067  public static void assertDiagnosticMessageEquals(
2068                          @NotNull final LDAPException exception,
2069                          @NotNull final String diagnosticMessage)
2070         throws AssertionError
2071  {
2072    if (exception.getDiagnosticMessage() == null)
2073    {
2074      throw new AssertionError(
2075           ERR_TEST_RESULT_MISSING_EXPECTED_DIAGNOSTIC_MESSAGE.get(
2076                StaticUtils.getExceptionMessage(exception), diagnosticMessage));
2077    }
2078
2079    if (! exception.getDiagnosticMessage().equals(diagnosticMessage))
2080    {
2081      throw new AssertionError(ERR_TEST_DIAGNOSTIC_MESSAGE_MISMATCH.get(
2082           StaticUtils.getExceptionMessage(exception), diagnosticMessage,
2083           exception.getDiagnosticMessage()));
2084    }
2085  }
2086
2087
2088
2089  /**
2090   * Ensures that the provided LDAP result has one or more referral URLs.
2091   *
2092   * @param  result  The LDAP result to examine.
2093   *
2094   * @throws  AssertionError  If the provided result does not have any referral
2095   *                          URLs.
2096   */
2097  public static void assertHasReferral(@NotNull final LDAPResult result)
2098         throws AssertionError
2099  {
2100    final String[] referralURLs = result.getReferralURLs();
2101    if ((referralURLs == null) || (referralURLs.length == 0))
2102    {
2103      throw new AssertionError(ERR_TEST_RESULT_MISSING_REFERRAL.get(
2104           String.valueOf(result)));
2105    }
2106  }
2107
2108
2109
2110  /**
2111   * Ensures that the provided LDAP exception has one or more referral URLs.
2112   *
2113   * @param  exception  The LDAP exception to examine.
2114   *
2115   * @throws  AssertionError  If the provided exception does not have any
2116   *                          referral URLs.
2117   */
2118  public static void assertHasReferral(@NotNull final LDAPException exception)
2119         throws AssertionError
2120  {
2121    final String[] referralURLs = exception.getReferralURLs();
2122    if ((referralURLs == null) || (referralURLs.length == 0))
2123    {
2124      throw new AssertionError(ERR_TEST_RESULT_MISSING_REFERRAL.get(
2125           StaticUtils.getExceptionMessage(exception)));
2126    }
2127  }
2128
2129
2130
2131  /**
2132   * Ensures that the provided LDAP result does not have any referral URLs.
2133   *
2134   * @param  result  The LDAP result to examine.
2135   *
2136   * @throws  AssertionError  If the provided result has one or more referral
2137   *                          URLs.
2138   */
2139  public static void assertMissingReferral(@NotNull final LDAPResult result)
2140         throws AssertionError
2141  {
2142    final String[] referralURLs = result.getReferralURLs();
2143    if ((referralURLs != null) && (referralURLs.length > 0))
2144    {
2145      throw new AssertionError(ERR_TEST_RESULT_HAS_REFERRAL.get(
2146           String.valueOf(result)));
2147    }
2148  }
2149
2150
2151
2152  /**
2153   * Ensures that the provided LDAP exception does not have any referral URLs.
2154   *
2155   * @param  exception  The LDAP exception to examine.
2156   *
2157   * @throws  AssertionError  If the provided exception has one or more referral
2158   *                          URLs.
2159   */
2160  public static void assertMissingReferral(
2161                          @NotNull final LDAPException exception)
2162         throws AssertionError
2163  {
2164    final String[] referralURLs = exception.getReferralURLs();
2165    if ((referralURLs != null) && (referralURLs.length > 0))
2166    {
2167      throw new AssertionError(ERR_TEST_RESULT_HAS_REFERRAL.get(
2168           StaticUtils.getExceptionMessage(exception)));
2169    }
2170  }
2171
2172
2173
2174  /**
2175   * Ensures that the provided LDAP result includes at least one control with
2176   * the specified OID.
2177   *
2178   * @param  result  The LDAP result to examine.
2179   * @param  oid     The OID of the control which is expected to be present in
2180   *                 the result.
2181   *
2182   * @return  The first control found with the specified OID.
2183   *
2184   * @throws  AssertionError  If the provided LDAP result does not include any
2185   *                          control with the specified OID.
2186   */
2187  @NotNull()
2188  public static Control assertHasControl(@NotNull final LDAPResult result,
2189                                         @NotNull final String oid)
2190         throws AssertionError
2191  {
2192    for (final Control c : result.getResponseControls())
2193    {
2194      if (c.getOID().equals(oid))
2195      {
2196        return c;
2197      }
2198    }
2199
2200    throw new AssertionError(ERR_TEST_RESULT_MISSING_CONTROL.get(
2201         String.valueOf(result), oid));
2202  }
2203
2204
2205
2206  /**
2207   * Ensures that the provided LDAP exception includes at least one control with
2208   * the specified OID.
2209   *
2210   * @param  exception  The LDAP exception to examine.
2211   * @param  oid        The OID of the control which is expected to be present
2212   *                    in the exception.
2213   *
2214   * @return  The first control found with the specified OID.
2215   *
2216   * @throws  AssertionError  If the provided LDAP exception does not include
2217   *                          any control with the specified OID.
2218   */
2219  @NotNull()
2220  public static Control assertHasControl(@NotNull final LDAPException exception,
2221                                         @NotNull final String oid)
2222         throws AssertionError
2223  {
2224    for (final Control c : exception.getResponseControls())
2225    {
2226      if (c.getOID().equals(oid))
2227      {
2228        return c;
2229      }
2230    }
2231
2232    throw new AssertionError(ERR_TEST_RESULT_MISSING_CONTROL.get(
2233         StaticUtils.getExceptionMessage(exception), oid));
2234  }
2235
2236
2237
2238  /**
2239   * Ensures that the provided search result entry includes at least one control
2240   * with the specified OID.
2241   *
2242   * @param  entry  The search result entry to examine.
2243   * @param  oid    The OID of the control which is expected to be present in
2244   *                the search result entry.
2245   *
2246   * @return  The first control found with the specified OID.
2247   *
2248   * @throws  AssertionError  If the provided search result entry does not
2249   *                          include any control with the specified OID.
2250   */
2251  @NotNull()
2252  public static Control assertHasControl(@NotNull final SearchResultEntry entry,
2253                                         @NotNull final String oid)
2254         throws AssertionError
2255  {
2256    for (final Control c : entry.getControls())
2257    {
2258      if (c.getOID().equals(oid))
2259      {
2260        return c;
2261      }
2262    }
2263
2264    throw new AssertionError(ERR_TEST_ENTRY_MISSING_CONTROL.get(
2265         String.valueOf(entry), oid));
2266  }
2267
2268
2269
2270  /**
2271   * Ensures that the provided search result reference includes at least one
2272   * control with the specified OID.
2273   *
2274   * @param  reference  The search result reference to examine.
2275   * @param  oid        The OID of the control which is expected to be present
2276   *                    in the search result reference.
2277   *
2278   * @return  The first control found with the specified OID.
2279   *
2280   * @throws  AssertionError  If the provided search result reference does not
2281   *                          include any control with the specified OID.
2282   */
2283  @NotNull()
2284  public static Control assertHasControl(
2285                             @NotNull final SearchResultReference reference,
2286                             @NotNull final String oid)
2287         throws AssertionError
2288  {
2289    for (final Control c : reference.getControls())
2290    {
2291      if (c.getOID().equals(oid))
2292      {
2293        return c;
2294      }
2295    }
2296
2297    throw new AssertionError(ERR_TEST_REF_MISSING_CONTROL.get(
2298         String.valueOf(reference), oid));
2299  }
2300
2301
2302
2303  /**
2304   * Ensures that the provided LDAP result does not include any control with
2305   * the specified OID.
2306   *
2307   * @param  result  The LDAP result to examine.
2308   * @param  oid     The OID of the control which is not expected to be present
2309   *                 in the result.
2310   *
2311   * @throws  AssertionError  If the provided LDAP result includes any control
2312   *                          with the specified OID.
2313   */
2314  public static void assertMissingControl(@NotNull final LDAPResult result,
2315                                          @NotNull final String oid)
2316         throws AssertionError
2317  {
2318    for (final Control c : result.getResponseControls())
2319    {
2320      if (c.getOID().equals(oid))
2321      {
2322        throw new AssertionError(ERR_TEST_RESULT_HAS_CONTROL.get(
2323             String.valueOf(result), oid));
2324      }
2325    }
2326  }
2327
2328
2329
2330  /**
2331   * Ensures that the provided LDAP exception does not include any control with
2332   * the specified OID.
2333   *
2334   * @param  exception  The LDAP exception to examine.
2335   * @param  oid        The OID of the control which is not expected to be
2336   *                    present in the exception.
2337   *
2338   * @throws  AssertionError  If the provided LDAP exception includes any
2339   *                          control with the specified OID.
2340   */
2341  public static void assertMissingControl(
2342                          @NotNull final LDAPException exception,
2343                          @NotNull final String oid)
2344         throws AssertionError
2345  {
2346    for (final Control c : exception.getResponseControls())
2347    {
2348      if (c.getOID().equals(oid))
2349      {
2350        throw new AssertionError(ERR_TEST_RESULT_HAS_CONTROL.get(
2351             StaticUtils.getExceptionMessage(exception), oid));
2352      }
2353    }
2354  }
2355
2356
2357
2358  /**
2359   * Ensures that the provided search result entry does not includes any control
2360   * with the specified OID.
2361   *
2362   * @param  entry  The search result entry to examine.
2363   * @param  oid    The OID of the control which is not expected to be present
2364   *                in the search result entry.
2365   *
2366   * @throws  AssertionError  If the provided search result entry includes any
2367   *                          control with the specified OID.
2368   */
2369  public static void assertMissingControl(
2370                          @NotNull final SearchResultEntry entry,
2371                          @NotNull final String oid)
2372         throws AssertionError
2373  {
2374    for (final Control c : entry.getControls())
2375    {
2376      if (c.getOID().equals(oid))
2377      {
2378        throw new AssertionError(ERR_TEST_ENTRY_HAS_CONTROL.get(
2379             String.valueOf(entry), oid));
2380      }
2381    }
2382  }
2383
2384
2385
2386  /**
2387   * Ensures that the provided search result reference does not includes any
2388   * control with the specified OID.
2389   *
2390   * @param  reference  The search result reference to examine.
2391   * @param  oid        The OID of the control which is not expected to be
2392   *                    present in the search result reference.
2393   *
2394   * @throws  AssertionError  If the provided search result reference includes
2395   *                          any control with the specified OID.
2396   */
2397  public static void assertMissingControl(
2398                          @NotNull final SearchResultReference reference,
2399                          @NotNull final String oid)
2400         throws AssertionError
2401  {
2402    for (final Control c : reference.getControls())
2403    {
2404      if (c.getOID().equals(oid))
2405      {
2406        throw new AssertionError(ERR_TEST_REF_HAS_CONTROL.get(
2407             String.valueOf(reference), oid));
2408      }
2409    }
2410  }
2411
2412
2413
2414  /**
2415   * Ensures that the provided search result indicates that at least one search
2416   * result entry was returned.
2417   *
2418   * @param  result  The search result to examine.
2419   *
2420   * @return  The number of search result entries that were returned.
2421   *
2422   * @throws  AssertionError  If the provided search result indicates that no
2423   *                          entries were returned.
2424   */
2425  public static int assertEntryReturned(@NotNull final SearchResult result)
2426         throws AssertionError
2427  {
2428    if (result.getEntryCount() == 0)
2429    {
2430      throw new AssertionError(ERR_TEST_SEARCH_NO_ENTRIES_RETURNED.get(
2431           String.valueOf(result)));
2432    }
2433
2434    return result.getEntryCount();
2435  }
2436
2437
2438
2439  /**
2440   * Ensures that the provided search exception indicates that at least one
2441   * search result entry was returned.
2442   *
2443   * @param  exception  The search exception to examine.
2444   *
2445   * @return  The number of search result entries that were returned.
2446   *
2447   * @throws  AssertionError  If the provided search exception indicates that no
2448   *                          entries were returned.
2449   */
2450  public static int assertEntryReturned(
2451                         @NotNull final LDAPSearchException exception)
2452         throws AssertionError
2453  {
2454    if (exception.getEntryCount() == 0)
2455    {
2456      throw new AssertionError(ERR_TEST_SEARCH_NO_ENTRIES_RETURNED.get(
2457           StaticUtils.getExceptionMessage(exception)));
2458    }
2459
2460    return exception.getEntryCount();
2461  }
2462
2463
2464
2465  /**
2466   * Ensures that the specified search result entry was included in provided
2467   * search result.
2468   *
2469   * @param  result  The search result to examine.
2470   * @param  dn      The DN of the entry expected to be included in the
2471   *                 search result.
2472   *
2473   * @return  The search result entry with the provided DN.
2474   *
2475   * @throws  LDAPException  If the provided string cannot be parsed as a valid
2476   *                         DN.
2477   *
2478   * @throws  AssertionError  If the specified entry was not included in the
2479   *                          set of entries that were returned, or if a search
2480   *                          result listener was used which makes the
2481   *                          determination impossible.
2482   */
2483  @NotNull()
2484  public static SearchResultEntry assertEntryReturned(
2485                                       @NotNull final SearchResult result,
2486                                       @NotNull final String dn)
2487         throws LDAPException, AssertionError
2488  {
2489    final DN parsedDN = new DN(dn);
2490
2491    final List<SearchResultEntry> entryList = result.getSearchEntries();
2492    if (entryList != null)
2493    {
2494      for (final SearchResultEntry e : entryList)
2495      {
2496        if (e.getParsedDN().equals(parsedDN))
2497        {
2498          return e;
2499        }
2500      }
2501    }
2502
2503    throw new AssertionError(ERR_TEST_SEARCH_ENTRY_NOT_RETURNED.get(
2504         String.valueOf(result), dn));
2505  }
2506
2507
2508
2509  /**
2510   * Ensures that the specified search result entry was included in provided
2511   * search exception.
2512   *
2513   * @param  exception  The search exception to examine.
2514   * @param  dn         The DN of the entry expected to be included in the
2515   *                    search exception.
2516   *
2517   * @return  The search result entry with the provided DN.
2518   *
2519   * @throws  LDAPException  If the provided string cannot be parsed as a valid
2520   *                         DN.
2521   *
2522   * @throws  AssertionError  If the specified entry was not included in the
2523   *                          set of entries that were returned, or if a search
2524   *                          result listener was used which makes the
2525   *                          determination impossible.
2526   */
2527  @NotNull()
2528  public static SearchResultEntry assertEntryReturned(
2529                     @NotNull final LDAPSearchException exception,
2530                     @NotNull final String dn)
2531         throws LDAPException, AssertionError
2532  {
2533    final DN parsedDN = new DN(dn);
2534
2535    final List<SearchResultEntry> entryList = exception.getSearchEntries();
2536    if (entryList != null)
2537    {
2538      for (final SearchResultEntry e : entryList)
2539      {
2540        if (e.getParsedDN().equals(parsedDN))
2541        {
2542          return e;
2543        }
2544      }
2545    }
2546
2547    throw new AssertionError(ERR_TEST_SEARCH_ENTRY_NOT_RETURNED.get(
2548         StaticUtils.getExceptionMessage(exception), dn));
2549  }
2550
2551
2552
2553  /**
2554   * Ensures that the provided search result indicates that no search result
2555   * entries were returned.
2556   *
2557   * @param  result  The search result to examine.
2558   *
2559   * @throws  AssertionError  If the provided search result indicates that one
2560   *                          or more entries were returned.
2561   */
2562  public static void assertNoEntriesReturned(@NotNull final SearchResult result)
2563         throws AssertionError
2564  {
2565    if (result.getEntryCount() > 0)
2566    {
2567      throw new AssertionError(ERR_TEST_SEARCH_ENTRIES_RETURNED.get(
2568           String.valueOf(result), result.getEntryCount()));
2569    }
2570  }
2571
2572
2573
2574  /**
2575   * Ensures that the provided search exception indicates that no search result
2576   * entries were returned.
2577   *
2578   * @param  exception  The search exception to examine.
2579   *
2580   * @throws  AssertionError  If the provided search exception indicates that
2581   *                          one or more entries were returned.
2582   */
2583  public static void assertNoEntriesReturned(
2584                          @NotNull final LDAPSearchException exception)
2585         throws AssertionError
2586  {
2587    if (exception.getEntryCount() > 0)
2588    {
2589      throw new AssertionError(ERR_TEST_SEARCH_ENTRIES_RETURNED.get(
2590           StaticUtils.getExceptionMessage(exception),
2591           exception.getEntryCount()));
2592    }
2593  }
2594
2595
2596
2597  /**
2598   * Ensures that the provided search result indicates that the expected number
2599   * of entries were returned.
2600   *
2601   * @param  result              The search result to examine.
2602   * @param  expectedEntryCount  The number of expected search result entries.
2603   *
2604   * @throws  AssertionError  If the number of entries returned does not match
2605   *                          the expected value.
2606   */
2607  public static void assertEntriesReturnedEquals(
2608                          @NotNull final SearchResult result,
2609                          final int expectedEntryCount)
2610         throws AssertionError
2611  {
2612    if (result.getEntryCount() != expectedEntryCount)
2613    {
2614      if (expectedEntryCount == 1)
2615      {
2616        throw new AssertionError(
2617             ERR_TEST_SEARCH_ENTRY_COUNT_MISMATCH_ONE_EXPECTED.get(
2618                  String.valueOf(result), result.getEntryCount()));
2619      }
2620      else
2621      {
2622        throw new AssertionError(
2623             ERR_TEST_SEARCH_ENTRY_COUNT_MISMATCH_MULTI_EXPECTED.get(
2624                  expectedEntryCount, String.valueOf(result),
2625                  result.getEntryCount()));
2626      }
2627    }
2628  }
2629
2630
2631
2632  /**
2633   * Ensures that the provided search exception indicates that the expected
2634   * number of entries were returned.
2635   *
2636   * @param  exception           The search exception to examine.
2637   * @param  expectedEntryCount  The number of expected search result entries.
2638   *
2639   * @throws  AssertionError  If the number of entries returned does not match
2640   *                          the expected value.
2641   */
2642  public static void assertEntriesReturnedEquals(
2643                          @NotNull final LDAPSearchException exception,
2644                          final int expectedEntryCount)
2645         throws AssertionError
2646  {
2647    if (exception.getEntryCount() != expectedEntryCount)
2648    {
2649      if (expectedEntryCount == 1)
2650      {
2651        throw new AssertionError(
2652             ERR_TEST_SEARCH_ENTRY_COUNT_MISMATCH_ONE_EXPECTED.get(
2653                  StaticUtils.getExceptionMessage(exception),
2654                  exception.getEntryCount()));
2655      }
2656      else
2657      {
2658        throw new AssertionError(
2659             ERR_TEST_SEARCH_ENTRY_COUNT_MISMATCH_MULTI_EXPECTED.get(
2660                  expectedEntryCount,
2661                  StaticUtils.getExceptionMessage(exception),
2662                  exception.getEntryCount()));
2663      }
2664    }
2665  }
2666
2667
2668
2669  /**
2670   * Ensures that the provided search result indicates that at least one search
2671   * result reference was returned.
2672   *
2673   * @param  result  The search result to examine.
2674   *
2675   * @return  The number of search result references that were returned.
2676   *
2677   * @throws  AssertionError  If the provided search result indicates that no
2678   *                          references were returned.
2679   */
2680  public static int assertReferenceReturned(@NotNull final SearchResult result)
2681         throws AssertionError
2682  {
2683    if (result.getReferenceCount() == 0)
2684    {
2685      throw new AssertionError(ERR_TEST_SEARCH_NO_REFS_RETURNED.get(
2686           String.valueOf(result)));
2687    }
2688
2689    return result.getReferenceCount();
2690  }
2691
2692
2693
2694  /**
2695   * Ensures that the provided search exception indicates that at least one
2696   * search result reference was returned.
2697   *
2698   * @param  exception  The search exception to examine.
2699   *
2700   * @return  The number of search result references that were returned.
2701   *
2702   * @throws  AssertionError  If the provided search exception indicates that no
2703   *                          references were returned.
2704   */
2705  public static int assertReferenceReturned(
2706                         @NotNull final LDAPSearchException exception)
2707         throws AssertionError
2708  {
2709    if (exception.getReferenceCount() == 0)
2710    {
2711      throw new AssertionError(ERR_TEST_SEARCH_NO_REFS_RETURNED.get(
2712           StaticUtils.getExceptionMessage(exception)));
2713    }
2714
2715    return exception.getReferenceCount();
2716  }
2717
2718
2719
2720  /**
2721   * Ensures that the provided search result indicates that no search result
2722   * references were returned.
2723   *
2724   * @param  result  The search result to examine.
2725   *
2726   * @throws  AssertionError  If the provided search result indicates that one
2727   *                          or more references were returned.
2728   */
2729  public static void assertNoReferencesReturned(
2730                          @NotNull final SearchResult result)
2731         throws AssertionError
2732  {
2733    if (result.getReferenceCount() > 0)
2734    {
2735      throw new AssertionError(ERR_TEST_SEARCH_REFS_RETURNED.get(
2736           String.valueOf(result), result.getReferenceCount()));
2737    }
2738  }
2739
2740
2741
2742  /**
2743   * Ensures that the provided search exception indicates that no search result
2744   * references were returned.
2745   *
2746   * @param  exception  The search exception to examine.
2747   *
2748   * @throws  AssertionError  If the provided search exception indicates that
2749   *                          one or more references were returned.
2750   */
2751  public static void assertNoReferencesReturned(
2752                          @NotNull final LDAPSearchException exception)
2753         throws AssertionError
2754  {
2755    if (exception.getReferenceCount() > 0)
2756    {
2757      throw new AssertionError(ERR_TEST_SEARCH_REFS_RETURNED.get(
2758           StaticUtils.getExceptionMessage(exception),
2759           exception.getReferenceCount()));
2760    }
2761  }
2762
2763
2764
2765  /**
2766   * Ensures that the provided search result indicates that the expected number
2767   * of references were returned.
2768   *
2769   * @param  result                  The search result to examine.
2770   * @param  expectedReferenceCount  The number of expected search result
2771   *                                 references.
2772   *
2773   * @throws  AssertionError  If the number of references returned does not
2774   *                          match the expected value.
2775   */
2776  public static void assertReferencesReturnedEquals(
2777                          @NotNull final SearchResult result,
2778                          final int expectedReferenceCount)
2779         throws AssertionError
2780  {
2781    if (result.getReferenceCount() != expectedReferenceCount)
2782    {
2783      if (expectedReferenceCount == 1)
2784      {
2785        throw new AssertionError(
2786             ERR_TEST_SEARCH_REF_COUNT_MISMATCH_ONE_EXPECTED.get(
2787                  String.valueOf(result), result.getReferenceCount()));
2788      }
2789      else
2790      {
2791        throw new AssertionError(
2792             ERR_TEST_SEARCH_REF_COUNT_MISMATCH_MULTI_EXPECTED.get(
2793                  expectedReferenceCount, String.valueOf(result),
2794                  result.getReferenceCount()));
2795      }
2796    }
2797  }
2798
2799
2800
2801  /**
2802   * Ensures that the provided search exception indicates that the expected
2803   * number of references were returned.
2804   *
2805   * @param  exception               The search exception to examine.
2806   * @param  expectedReferenceCount  The number of expected search result
2807   *                                 references.
2808   *
2809   * @throws  AssertionError  If the number of references returned does not
2810   *                          match the expected value.
2811   */
2812  public static void assertReferencesReturnedEquals(
2813                          @NotNull final LDAPSearchException exception,
2814                          final int expectedReferenceCount)
2815         throws AssertionError
2816  {
2817    if (exception.getReferenceCount() != expectedReferenceCount)
2818    {
2819      if (expectedReferenceCount == 1)
2820      {
2821        throw new AssertionError(
2822             ERR_TEST_SEARCH_REF_COUNT_MISMATCH_ONE_EXPECTED.get(
2823                  StaticUtils.getExceptionMessage(exception),
2824                  exception.getReferenceCount()));
2825      }
2826      else
2827      {
2828        throw new AssertionError(
2829             ERR_TEST_SEARCH_REF_COUNT_MISMATCH_MULTI_EXPECTED.get(
2830                  expectedReferenceCount,
2831                  StaticUtils.getExceptionMessage(exception),
2832                  exception.getReferenceCount()));
2833      }
2834    }
2835  }
2836
2837
2838
2839  /**
2840   * Ensures that the two provided strings represent the same DN.
2841   *
2842   * @param  s1  The first string to compare.
2843   * @param  s2  The second string to compare.
2844   *
2845   * @throws  AssertionError  If either string doesn't represent a valid DN, or
2846   *                          if they do not represent the same DN.
2847   */
2848  public static void assertDNsEqual(@NotNull final String s1,
2849                                    @NotNull final String s2)
2850         throws AssertionError
2851  {
2852    final DN dn1;
2853    try
2854    {
2855      dn1 = new DN(s1);
2856    }
2857    catch (final Exception e)
2858    {
2859      throw new AssertionError(ERR_TEST_VALUE_NOT_VALID_DN.get(s1,
2860           StaticUtils.getExceptionMessage(e)));
2861    }
2862
2863    final DN dn2;
2864    try
2865    {
2866      dn2 = new DN(s2);
2867    }
2868    catch (final Exception e)
2869    {
2870      throw new AssertionError(ERR_TEST_VALUE_NOT_VALID_DN.get(s2,
2871           StaticUtils.getExceptionMessage(e)));
2872    }
2873
2874    if (! dn1.equals(dn2))
2875    {
2876      throw new AssertionError(ERR_TEST_DNS_NOT_EQUAL.get(s1, s2));
2877    }
2878  }
2879}