blob: 25f75a2c049ce6f52a60ab9123681751f34d10d9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.shared.ldap.subtree;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import org.apache.directory.shared.ldap.entry.StringValue;
import org.apache.directory.shared.ldap.filter.AndNode;
import org.apache.directory.shared.ldap.filter.BranchNode;
import org.apache.directory.shared.ldap.filter.EqualityNode;
import org.apache.directory.shared.ldap.filter.ExprNode;
import org.apache.directory.shared.ldap.filter.FilterParser;
import org.apache.directory.shared.ldap.filter.NotNode;
import org.apache.directory.shared.ldap.filter.OrNode;
import org.apache.directory.shared.ldap.filter.SimpleNode;
import org.apache.directory.shared.ldap.name.DN;
import org.apache.directory.shared.ldap.subtree.SubtreeSpecification;
import org.apache.directory.shared.ldap.subtree.SubtreeSpecificationParser;
import org.junit.Test;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
/**
* Unit tests class for Subtree Specification parser (wrapper).
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class SubtreeSpecificationParserTest
{
/** A valid empty specification with single white space between brackets */
private static final String EMPTY_SPEC = "{ }";
/** A valid specification only with base set */
private static final String SPEC_WITH_BASE = "{ base \"ou=system\" }";
/** An invalid specification with missing white space and base set */
private static final String INVALID_SPEC_WITH_BASE_AND_MISSING_WS = "{ base\"ou=system\"}";
/** A valid specification with some specific exclusions set */
private static final String SPEC_WITH_SPECIFICEXCLUSIONS = "{ specificExclusions { chopAfter:\"ef=gh\", chopBefore:\"ab=cd\" } }";
/** A valid specification with empty specific exclusions set */
private static final String SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS = "{ specificExclusions { } }";
/** A valid specification with minimum and maximum set */
private static final String SPEC_WITH_MINIMUM_AND_MAXIMUM = "{ minimum 1, maximum 2 }";
/** A valid specification with base and minimum and maximum set */
private static final String SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=ORGANIZATION UNIT\", minimum 1, maximum 2 }";
/**
* A valid specification with base and specific exclusions and minimum and
* maximum set
*/
private static final String SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=people\", specificExclusions { chopBefore:\"x=y\""
+ ", chopAfter:\"k=l\", chopBefore:\"y=z\", chopAfter:\"l=m\" }, minimum 7, maximum 77 }";
/** A valid specification with refinement set */
private static final String SPEC_WITH_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ and:{ item:1.2.3"
+ ", or:{ item:4.5.6, item:person-7 } }, not:{ item:10.11.12 } } }";
/** A valid specification with base and an empty refinement set */
private static final String SPEC_WITH_BASE_AND_EMPTY_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ } }";
/** A valid specification with ALL IN ONE */
private static final String SPEC_WITH_ALL_IN_ONE = "{ base \"ou=departments\""
+ ", specificExclusions { chopBefore:\"x=y\", chopAfter:\"k=l\", chopBefore:\"y=z\", chopAfter:\"l=m\" }"
+ ", minimum 7, maximum 77"
+ ", specificationFilter and:{ and:{ item:1.2.3, or:{ item:4.5.6, item:7.8.9 } }, not:{ item:10.11.12 } } }";
/** An valid specification with unordinary component order */
private static final String SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER = "{ base \"ou=system\", minimum 3, specificExclusions { chopBefore:\"x=y\" } }";
/** An invalid specification with completely unrelated content */
private static final String INVALID_SILLY_THING = "How much wood would a wood chuck chuck if a wood chuck would chuck wood?";
/** A valid specification with filter expression */
private static final String SPEC_WITH_FILTER = "{ base \"ou=system\", specificationFilter (&(cn=test)(sn=test)) }";
/** the ss parser wrapper */
SubtreeSpecificationParser parser;
/** holds multithreaded success value */
boolean isSuccessMultithreaded = true;
/**
* Creates a SubtreeSpecificationParserTest instance.
*/
public SubtreeSpecificationParserTest()
{
super();
parser = new SubtreeSpecificationParser( null );
}
/**
* Tests the parser with a valid empty specification.
*/
@Test
public void testEmptySpec() throws Exception
{
SubtreeSpecification ss = parser.parse( EMPTY_SPEC );
assertNotNull( ss );
// try a second time
ss = parser.parse( EMPTY_SPEC );
assertNotNull( ss );
// try a third time
ss = parser.parse( EMPTY_SPEC );
assertNotNull( ss );
}
/**
* Tests the parser with a valid specification with base set.
*/
@Test
public void testSpecWithBase() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE );
assertNotNull( ss );
assertEquals( "ou=system", ss.getBase().toString() );
}
/**
* Tests the parser with an invalid specification with missing white spaces
* and base set.
*/
@Test
public void testInvalidSpecWithBaseAndMissingWS() throws Exception
{
try
{
parser.parse( INVALID_SPEC_WITH_BASE_AND_MISSING_WS );
fail( "testInvalidSpecWithBaseAndMissingWS() should never come here..." );
}
catch ( ParseException e )
{
assertNotNull( e );
}
}
/**
* Tests the parser with a valid specification with some specific exclusions
* set.
*/
@Test
public void testSpecWithSpecificExclusions() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
assertFalse( ss.getChopBeforeExclusions().isEmpty() );
assertFalse( ss.getChopAfterExclusions().isEmpty() );
assertTrue( ss.getChopBeforeExclusions().contains( new DN( "ab=cd" ) ) );
assertTrue( ss.getChopAfterExclusions().contains( new DN( "ef=gh" ) ) );
// try a second time
ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
assertFalse( ss.getChopBeforeExclusions().isEmpty() );
assertFalse( ss.getChopAfterExclusions().isEmpty() );
assertTrue( ss.getChopBeforeExclusions().contains( new DN( "ab=cd" ) ) );
assertTrue( ss.getChopAfterExclusions().contains( new DN( "ef=gh" ) ) );
// try a third time
ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
assertFalse( ss.getChopBeforeExclusions().isEmpty() );
assertFalse( ss.getChopAfterExclusions().isEmpty() );
assertTrue( ss.getChopBeforeExclusions().contains( new DN( "ab=cd" ) ) );
assertTrue( ss.getChopAfterExclusions().contains( new DN( "ef=gh" ) ) );
}
/**
* Tests the parser with a valid specification with an empty specific
* exclusions set.
*/
@Test
public void testSpecWithEmptySpecificExclusions() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS );
assertNotNull( ss );
assertTrue( ss.getChopBeforeExclusions().isEmpty() );
}
/**
* Tests the parser with a valid specification with minimum and maximum set.
*/
@Test
public void testSpecWithMinimumAndMaximum() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
assertEquals( 1, ss.getMinBaseDistance() );
assertEquals( 2, ss.getMaxBaseDistance() );
// try a second time
ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
assertEquals( 1, ss.getMinBaseDistance() );
assertEquals( 2, ss.getMaxBaseDistance() );
// try a third time
ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
assertEquals( 1, ss.getMinBaseDistance() );
assertEquals( 2, ss.getMaxBaseDistance() );
}
/**
* Tests the parser with a valid specification with base and minimum and
* maximum set.
*/
@Test
public void testWithBaseAndMinimumAndMaximum() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM );
assertEquals( new DN( "ou=ORGANIZATION UNIT" ), ss.getBase() );
assertEquals( 1, ss.getMinBaseDistance() );
assertEquals( 2, ss.getMaxBaseDistance() );
}
/**
* Tests the parser with a valid specification with base and specific
* exclusions and minimum and maximum set.
*/
@Test
public void testSpecWithBaseAndSpecificExclusionsAndMinimumAndMaximum() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM );
assertNotNull( ss );
assertEquals( "ou=people", ss.getBase().toString() );
assertTrue( ss.getChopBeforeExclusions().contains( new DN( "x=y" ) ) );
assertTrue( ss.getChopBeforeExclusions().contains( new DN( "y=z" ) ) );
assertTrue( ss.getChopAfterExclusions().contains( new DN( "k=l" ) ) );
assertTrue( ss.getChopAfterExclusions().contains( new DN( "l=m" ) ) );
assertEquals( 7, ss.getMinBaseDistance() );
assertEquals( 77, ss.getMaxBaseDistance() );
}
/**
* Tests the parser with a valid specification with refinement set.
*/
@Test
public void testSpecWithRefinement() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_REFINEMENT );
SimpleNode<String> n1 = new EqualityNode<String>( "objectClass", new StringValue( "1.2.3" ) );
SimpleNode<String> n2 = new EqualityNode<String>( "objectClass", new StringValue( "4.5.6" ) );
SimpleNode<String> n3 = new EqualityNode<String>( "objectClass", new StringValue( "person-7" ) );
BranchNode n4 = new OrNode();
n4.addNode( n2 );
n4.addNode( n3 );
BranchNode n5 = new AndNode();
n5.addNode( n1 );
n5.addNode( n4 );
SimpleNode<String> n6 = new EqualityNode<String>( "objectClass", new StringValue( "10.11.12" ) );
BranchNode n7 = new NotNode();
n7.addNode( n6 );
BranchNode n8 = new AndNode();
n8.addNode( n5 );
n8.addNode( n7 );
assertEquals( n8, ss.getRefinement() );
}
/**
* Tests the parser with a valid specification with base and empty
* refinement set.
*/
@Test
public void testSpecWithBaseAndEmptyRefinement() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_EMPTY_REFINEMENT );
assertEquals( "ou=system", ss.getBase().toString() );
}
/**
* Tests the parser with a valid specification with all components set.
*/
@Test
public void testSpecWithAllInOne() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_ALL_IN_ONE );
assertNotNull( ss );
}
/**
* Tests the parser with a valid specification with unordinary component
* order.
*/
@Test
public void testSpecOrderOfComponentsDoesNotMatter() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER );
assertNotNull( ss );
}
/**
* Tests the parser with an invalid specification with silly things in.
*/
@Test
public void testInvalidSillyThing() throws Exception
{
try
{
parser.parse( INVALID_SILLY_THING );
fail( "testInvalidSillyThing() should never come here..." );
}
catch ( ParseException e )
{
assertNotNull( e );
}
}
/**
* Tests the parser with a valid specification with refinement set.
*/
@Test
public void testSpecWithFilter() throws Exception
{
SubtreeSpecification ss = parser.parse( SPEC_WITH_FILTER );
ExprNode filter = FilterParser.parse( "(&(cn=test)(sn=test))" );
assertEquals( filter, ss.getRefinement() );
}
/**
* Test reusability, especially if the state is resetted.
*/
@Test
public void testReusabiltiy() throws Exception
{
DN firstDN = new DN("k=l");
String firstExclusion = "{ specificExclusions { chopAfter:\"k=l\" } }";
SubtreeSpecification firstSpec = parser.parse( firstExclusion );
assertEquals( 1, firstSpec.getChopAfterExclusions().size() );
assertEquals( firstDN, firstSpec.getChopAfterExclusions().iterator().next() );
DN secondDN = new DN("x=y");
String secondExclusion = "{ specificExclusions { chopAfter:\"x=y\" } }";
SubtreeSpecification secondSpec = parser.parse( secondExclusion );
assertEquals( 1, secondSpec.getChopAfterExclusions().size() );
assertEquals( secondDN, secondSpec.getChopAfterExclusions().iterator().next() );
}
/**
* Tests the multithreaded use of a single parser.
*/
@Test
public void testMultiThreaded() throws Exception
{
// start up and track all threads (40 threads)
List<Thread> threads = new ArrayList<Thread>();
for ( int ii = 0; ii < 10; ii++ )
{
Thread t0 = new Thread( new ParseSpecification( EMPTY_SPEC ) );
Thread t1 = new Thread( new ParseSpecification( SPEC_WITH_SPECIFICEXCLUSIONS ) );
Thread t2 = new Thread( new ParseSpecification( SPEC_WITH_MINIMUM_AND_MAXIMUM ) );
Thread t3 = new Thread( new ParseSpecification( SPEC_WITH_ALL_IN_ONE ) );
threads.add( t0 );
threads.add( t1 );
threads.add( t2 );
threads.add( t3 );
t0.start();
t1.start();
t2.start();
t3.start();
}
// wait until all threads have died
boolean hasLiveThreads = false;
do
{
hasLiveThreads = false;
for ( int ii = 0; ii < threads.size(); ii++ )
{
Thread t = threads.get( ii );
hasLiveThreads = hasLiveThreads || t.isAlive();
}
}
while ( hasLiveThreads );
// check that no one thread failed to parse and generate a SS object
assertTrue( isSuccessMultithreaded );
}
/**
* Used to test multithreaded use of a single parser.
*/
class ParseSpecification implements Runnable
{
private final String specStr;
SubtreeSpecification result;
public ParseSpecification(String specStr)
{
this.specStr = specStr;
}
public void run()
{
try
{
result = parser.parse( specStr );
}
catch ( ParseException e )
{
e.printStackTrace();
}
isSuccessMultithreaded = isSuccessMultithreaded && ( result != null );
}
}
}