18
18
package org .apache .hadoop .crypto .key .kms ;
19
19
20
20
import static org .apache .hadoop .crypto .key .KeyProviderCryptoExtension .EncryptedKeyVersion ;
21
+ import static org .apache .hadoop .test .LambdaTestUtils .intercept ;
21
22
import static org .junit .Assert .assertEquals ;
22
23
import static org .junit .Assert .assertTrue ;
23
24
import static org .junit .Assert .fail ;
26
27
import static org .mockito .Mockito .verify ;
27
28
28
29
import java .io .IOException ;
30
+ import java .net .ConnectException ;
29
31
import java .net .NoRouteToHostException ;
30
32
import java .net .URI ;
31
33
import java .net .UnknownHostException ;
32
34
import java .security .GeneralSecurityException ;
33
35
import java .security .NoSuchAlgorithmException ;
34
36
37
+ import javax .net .ssl .SSLHandshakeException ;
38
+
35
39
import org .apache .hadoop .conf .Configuration ;
36
40
import org .apache .hadoop .crypto .key .KeyProvider ;
37
41
import org .apache .hadoop .crypto .key .KeyProvider .Options ;
44
48
import org .apache .hadoop .security .authorize .AuthorizationException ;
45
49
import org .junit .After ;
46
50
import org .junit .BeforeClass ;
51
+ import org .junit .Rule ;
47
52
import org .junit .Test ;
53
+ import org .junit .rules .Timeout ;
48
54
import org .mockito .Mockito ;
49
55
50
56
import com .google .common .collect .Sets ;
51
57
52
58
public class TestLoadBalancingKMSClientProvider {
53
59
60
+ @ Rule
61
+ public Timeout testTimeout = new Timeout (30 * 1000 );
62
+
54
63
@ BeforeClass
55
64
public static void setup () throws IOException {
56
65
SecurityUtil .setTokenServiceUseIp (false );
@@ -638,4 +647,74 @@ public void testClientRetriesWithAuthenticationExceptionWrappedinIOException()
638
647
verify (p2 , Mockito .times (1 )).createKey (Mockito .eq ("test3" ),
639
648
Mockito .any (Options .class ));
640
649
}
650
+
651
+ /**
652
+ * Tests the operation succeeds second time after SSLHandshakeException.
653
+ * @throws Exception
654
+ */
655
+ @ Test
656
+ public void testClientRetriesWithSSLHandshakeExceptionSucceedsSecondTime ()
657
+ throws Exception {
658
+ Configuration conf = new Configuration ();
659
+ conf .setInt (
660
+ CommonConfigurationKeysPublic .KMS_CLIENT_FAILOVER_MAX_RETRIES_KEY , 3 );
661
+ final String keyName = "test" ;
662
+ KMSClientProvider p1 = mock (KMSClientProvider .class );
663
+ when (p1 .createKey (Mockito .anyString (), Mockito .any (Options .class )))
664
+ .thenThrow (new SSLHandshakeException ("p1" ))
665
+ .thenReturn (new KMSClientProvider .KMSKeyVersion (keyName , "v1" ,
666
+ new byte [0 ]));
667
+ KMSClientProvider p2 = mock (KMSClientProvider .class );
668
+ when (p2 .createKey (Mockito .anyString (), Mockito .any (Options .class )))
669
+ .thenThrow (new ConnectException ("p2" ));
670
+
671
+ when (p1 .getKMSUrl ()).thenReturn ("p1" );
672
+ when (p2 .getKMSUrl ()).thenReturn ("p2" );
673
+
674
+ LoadBalancingKMSClientProvider kp = new LoadBalancingKMSClientProvider (
675
+ new KMSClientProvider [] {p1 , p2 }, 0 , conf );
676
+
677
+ kp .createKey (keyName , new Options (conf ));
678
+ verify (p1 , Mockito .times (2 )).createKey (Mockito .eq (keyName ),
679
+ Mockito .any (Options .class ));
680
+ verify (p2 , Mockito .times (1 )).createKey (Mockito .eq (keyName ),
681
+ Mockito .any (Options .class ));
682
+ }
683
+
684
+ /**
685
+ * Tests the operation fails at every attempt after SSLHandshakeException.
686
+ * @throws Exception
687
+ */
688
+ @ Test
689
+ public void testClientRetriesWithSSLHandshakeExceptionFailsAtEveryAttempt ()
690
+ throws Exception {
691
+ Configuration conf = new Configuration ();
692
+ conf .setInt (
693
+ CommonConfigurationKeysPublic .KMS_CLIENT_FAILOVER_MAX_RETRIES_KEY , 2 );
694
+ final String keyName = "test" ;
695
+ final String exceptionMessage = "p1 exception message" ;
696
+ KMSClientProvider p1 = mock (KMSClientProvider .class );
697
+ Exception originalSslEx = new SSLHandshakeException (exceptionMessage );
698
+ when (p1 .createKey (Mockito .anyString (), Mockito .any (Options .class )))
699
+ .thenThrow (originalSslEx );
700
+ KMSClientProvider p2 = mock (KMSClientProvider .class );
701
+ when (p2 .createKey (Mockito .anyString (), Mockito .any (Options .class )))
702
+ .thenThrow (new ConnectException ("p2 exception message" ));
703
+
704
+ when (p1 .getKMSUrl ()).thenReturn ("p1" );
705
+ when (p2 .getKMSUrl ()).thenReturn ("p2" );
706
+
707
+ LoadBalancingKMSClientProvider kp = new LoadBalancingKMSClientProvider (
708
+ new KMSClientProvider [] {p1 , p2 }, 0 , conf );
709
+
710
+ Exception interceptedEx = intercept (ConnectException .class ,
711
+ "SSLHandshakeException: " + exceptionMessage ,
712
+ ()-> kp .createKey (keyName , new Options (conf )));
713
+ assertEquals (originalSslEx , interceptedEx .getCause ());
714
+
715
+ verify (p1 , Mockito .times (2 )).createKey (Mockito .eq (keyName ),
716
+ Mockito .any (Options .class ));
717
+ verify (p2 , Mockito .times (1 )).createKey (Mockito .eq (keyName ),
718
+ Mockito .any (Options .class ));
719
+ }
641
720
}
0 commit comments