2626import java .util .Arrays ;
2727import java .util .List ;
2828
29+ import javax .naming .CommunicationException ;
2930import javax .naming .NamingEnumeration ;
3031import javax .naming .NamingException ;
3132import javax .naming .directory .Attribute ;
@@ -46,21 +47,15 @@ public class TestLdapGroupsMapping {
4647 private DirContext mockContext ;
4748
4849 private LdapGroupsMapping mappingSpy = spy (new LdapGroupsMapping ());
50+ private NamingEnumeration mockUserNamingEnum = mock (NamingEnumeration .class );
51+ private NamingEnumeration mockGroupNamingEnum = mock (NamingEnumeration .class );
52+ private String [] testGroups = new String [] {"group1" , "group2" };
4953
5054 @ Before
5155 public void setupMocks () throws NamingException {
5256 mockContext = mock (DirContext .class );
5357 doReturn (mockContext ).when (mappingSpy ).getDirContext ();
54-
55- NamingEnumeration mockUserNamingEnum = mock (NamingEnumeration .class );
56- NamingEnumeration mockGroupNamingEnum = mock (NamingEnumeration .class );
57-
58- // The search functionality of the mock context is reused, so we will
59- // return the user NamingEnumeration first, and then the group
60- when (mockContext .search (anyString (), anyString (), any (Object [].class ),
61- any (SearchControls .class )))
62- .thenReturn (mockUserNamingEnum , mockGroupNamingEnum );
63-
58+
6459 SearchResult mockUserResult = mock (SearchResult .class );
6560 // We only ever call hasMoreElements once for the user NamingEnum, so
6661 // we can just have one return value
@@ -76,23 +71,57 @@ public void setupMocks() throws NamingException {
7671
7772 // Define the attribute for the name of the first group
7873 Attribute group1Attr = new BasicAttribute ("cn" );
79- group1Attr .add ("group1" );
74+ group1Attr .add (testGroups [ 0 ] );
8075 Attributes group1Attrs = new BasicAttributes ();
8176 group1Attrs .put (group1Attr );
8277
8378 // Define the attribute for the name of the second group
8479 Attribute group2Attr = new BasicAttribute ("cn" );
85- group2Attr .add ("group2" );
80+ group2Attr .add (testGroups [ 1 ] );
8681 Attributes group2Attrs = new BasicAttributes ();
8782 group2Attrs .put (group2Attr );
8883
8984 // This search result gets reused, so return group1, then group2
9085 when (mockGroupResult .getAttributes ()).thenReturn (group1Attrs , group2Attrs );
91-
9286 }
9387
9488 @ Test
9589 public void testGetGroups () throws IOException , NamingException {
90+ // The search functionality of the mock context is reused, so we will
91+ // return the user NamingEnumeration first, and then the group
92+ when (mockContext .search (anyString (), anyString (), any (Object [].class ),
93+ any (SearchControls .class )))
94+ .thenReturn (mockUserNamingEnum , mockGroupNamingEnum );
95+
96+ doTestGetGroups (Arrays .asList (testGroups ), 2 );
97+ }
98+
99+ @ Test
100+ public void testGetGroupsWithConnectionClosed () throws IOException , NamingException {
101+ // The case mocks connection is closed/gc-ed, so the first search call throws CommunicationException,
102+ // then after reconnected return the user NamingEnumeration first, and then the group
103+ when (mockContext .search (anyString (), anyString (), any (Object [].class ),
104+ any (SearchControls .class )))
105+ .thenThrow (new CommunicationException ("Connection is closed" ))
106+ .thenReturn (mockUserNamingEnum , mockGroupNamingEnum );
107+
108+ // Although connection is down but after reconnected it still should retrieve the result groups
109+ doTestGetGroups (Arrays .asList (testGroups ), 1 + 2 ); // 1 is the first failure call
110+ }
111+
112+ @ Test
113+ public void testGetGroupsWithLdapDown () throws IOException , NamingException {
114+ // This mocks the case where Ldap server is down, and always throws CommunicationException
115+ when (mockContext .search (anyString (), anyString (), any (Object [].class ),
116+ any (SearchControls .class )))
117+ .thenThrow (new CommunicationException ("Connection is closed" ));
118+
119+ // Ldap server is down, no groups should be retrieved
120+ doTestGetGroups (Arrays .asList (new String [] {}),
121+ 1 + LdapGroupsMapping .RECONNECT_RETRY_COUNT ); // 1 is the first normal call
122+ }
123+
124+ private void doTestGetGroups (List <String > expectedGroups , int searchTimes ) throws IOException , NamingException {
96125 Configuration conf = new Configuration ();
97126 // Set this, so we don't throw an exception
98127 conf .set (LdapGroupsMapping .LDAP_URL_KEY , "ldap://test" );
@@ -102,10 +131,10 @@ public void testGetGroups() throws IOException, NamingException {
102131 // regardless of input
103132 List <String > groups = mappingSpy .getGroups ("some_user" );
104133
105- Assert .assertEquals (Arrays . asList ( "group1" , "group2" ) , groups );
134+ Assert .assertEquals (expectedGroups , groups );
106135
107136 // We should have searched for a user, and then two groups
108- verify (mockContext , times (2 )).search (anyString (),
137+ verify (mockContext , times (searchTimes )).search (anyString (),
109138 anyString (),
110139 any (Object [].class ),
111140 any (SearchControls .class ));
0 commit comments