/** * 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.hadoop.fs.s3a; import static org.apache.hadoop.fs.s3a.Constants.*; import static org.apache.hadoop.fs.s3a.S3ATestConstants.*; import static org.apache.hadoop.fs.s3a.S3ATestUtils.*; import static org.apache.hadoop.fs.s3a.S3AUtils.*; import static org.junit.Assert.*; import java.io.IOException; import java.net.URI; import java.util.Arrays; import java.util.List; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.EnvironmentVariableCredentialsProvider; import com.amazonaws.auth.InstanceProfileCredentialsProvider; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; /** * Unit tests for {@link Constants#AWS_CREDENTIALS_PROVIDER} logic. */ public class TestS3AAWSCredentialsProvider { @Rule public ExpectedException exception = ExpectedException.none(); @Test public void testProviderWrongClass() throws Exception { expectProviderInstantiationFailure(this.getClass().getName(), NOT_AWS_PROVIDER); } @Test public void testProviderAbstractClass() throws Exception { expectProviderInstantiationFailure(AbstractProvider.class.getName(), ABSTRACT_PROVIDER); } @Test public void testProviderNotAClass() throws Exception { expectProviderInstantiationFailure("NoSuchClass", "ClassNotFoundException"); } @Test public void testProviderConstructorError() throws Exception { expectProviderInstantiationFailure( ConstructorSignatureErrorProvider.class.getName(), CONSTRUCTOR_EXCEPTION); } @Test public void testProviderFailureError() throws Exception { expectProviderInstantiationFailure( ConstructorFailureProvider.class.getName(), INSTANTIATION_EXCEPTION); } @Test public void testInstantiationChain() throws Throwable { Configuration conf = new Configuration(); conf.set(AWS_CREDENTIALS_PROVIDER, TemporaryAWSCredentialsProvider.NAME + ", \t" + SimpleAWSCredentialsProvider.NAME + " ,\n " + AnonymousAWSCredentialsProvider.NAME); Path testFile = new Path( conf.getTrimmed(KEY_CSVTEST_FILE, DEFAULT_CSVTEST_FILE)); URI uri = testFile.toUri(); AWSCredentialProviderList list = S3AUtils.createAWSCredentialProviderSet( uri, conf, uri); List<Class<? extends AWSCredentialsProvider>> expectedClasses = Arrays.asList( TemporaryAWSCredentialsProvider.class, SimpleAWSCredentialsProvider.class, AnonymousAWSCredentialsProvider.class); assertCredentialProviders(expectedClasses, list); } @Test public void testDefaultChain() throws Exception { URI uri1 = new URI("s3a://bucket1"), uri2 = new URI("s3a://bucket2"); Configuration conf = new Configuration(); AWSCredentialProviderList list1 = S3AUtils.createAWSCredentialProviderSet( uri1, conf, uri1); AWSCredentialProviderList list2 = S3AUtils.createAWSCredentialProviderSet( uri2, conf, uri2); List<Class<? extends AWSCredentialsProvider>> expectedClasses = Arrays.asList( BasicAWSCredentialsProvider.class, EnvironmentVariableCredentialsProvider.class, SharedInstanceProfileCredentialsProvider.class); assertCredentialProviders(expectedClasses, list1); assertCredentialProviders(expectedClasses, list2); assertSameInstanceProfileCredentialsProvider(list1.getProviders().get(2), list2.getProviders().get(2)); } @Test public void testConfiguredChain() throws Exception { URI uri1 = new URI("s3a://bucket1"), uri2 = new URI("s3a://bucket2"); Configuration conf = new Configuration(); List<Class<? extends AWSCredentialsProvider>> expectedClasses = Arrays.asList( EnvironmentVariableCredentialsProvider.class, SharedInstanceProfileCredentialsProvider.class, AnonymousAWSCredentialsProvider.class); conf.set(AWS_CREDENTIALS_PROVIDER, buildClassListString(expectedClasses)); AWSCredentialProviderList list1 = S3AUtils.createAWSCredentialProviderSet( uri1, conf, uri1); AWSCredentialProviderList list2 = S3AUtils.createAWSCredentialProviderSet( uri2, conf, uri2); assertCredentialProviders(expectedClasses, list1); assertCredentialProviders(expectedClasses, list2); assertSameInstanceProfileCredentialsProvider(list1.getProviders().get(1), list2.getProviders().get(1)); } @Test public void testConfiguredChainUsesSharedInstanceProfile() throws Exception { URI uri1 = new URI("s3a://bucket1"), uri2 = new URI("s3a://bucket2"); Configuration conf = new Configuration(); List<Class<? extends AWSCredentialsProvider>> expectedClasses = Arrays.<Class<? extends AWSCredentialsProvider>>asList( InstanceProfileCredentialsProvider.class); conf.set(AWS_CREDENTIALS_PROVIDER, buildClassListString(expectedClasses)); AWSCredentialProviderList list1 = S3AUtils.createAWSCredentialProviderSet( uri1, conf, uri1); AWSCredentialProviderList list2 = S3AUtils.createAWSCredentialProviderSet( uri2, conf, uri2); assertCredentialProviders(expectedClasses, list1); assertCredentialProviders(expectedClasses, list2); assertSameInstanceProfileCredentialsProvider(list1.getProviders().get(0), list2.getProviders().get(0)); } /** * A credential provider declared as abstract, so it cannot be instantiated. */ static abstract class AbstractProvider implements AWSCredentialsProvider { } /** * A credential provider whose constructor signature doesn't match. */ static class ConstructorSignatureErrorProvider implements AWSCredentialsProvider { @SuppressWarnings("unused") public ConstructorSignatureErrorProvider(String str) { } @Override public AWSCredentials getCredentials() { return null; } @Override public void refresh() { } } /** * A credential provider whose constructor raises an NPE. */ static class ConstructorFailureProvider implements AWSCredentialsProvider { @SuppressWarnings("unused") public ConstructorFailureProvider() { throw new NullPointerException("oops"); } @Override public AWSCredentials getCredentials() { return null; } @Override public void refresh() { } } /** * Declare what exception to raise, and the text which must be found * in it. * @param exceptionClass class of exception * @param text text in exception */ private void expectException(Class<? extends Throwable> exceptionClass, String text) { exception.expect(exceptionClass); exception.expectMessage(text); } private void expectProviderInstantiationFailure(String option, String expectedErrorText) throws IOException { Configuration conf = new Configuration(); conf.set(AWS_CREDENTIALS_PROVIDER, option); Path testFile = new Path( conf.getTrimmed(KEY_CSVTEST_FILE, DEFAULT_CSVTEST_FILE)); expectException(IOException.class, expectedErrorText); URI uri = testFile.toUri(); S3AUtils.createAWSCredentialProviderSet(uri, conf, uri); } /** * Asserts expected provider classes in list. * @param expectedClasses expected provider classes * @param list providers to check */ private static void assertCredentialProviders( List<Class<? extends AWSCredentialsProvider>> expectedClasses, AWSCredentialProviderList list) { assertNotNull(list); List<AWSCredentialsProvider> providers = list.getProviders(); assertEquals(expectedClasses.size(), providers.size()); for (int i = 0; i < expectedClasses.size(); ++i) { Class<? extends AWSCredentialsProvider> expectedClass = expectedClasses.get(i); AWSCredentialsProvider provider = providers.get(i); assertNotNull( String.format("At position %d, expected class is %s, but found null.", i, expectedClass), provider); assertTrue( String.format("At position %d, expected class is %s, but found %s.", i, expectedClass, provider.getClass()), expectedClass.isAssignableFrom(provider.getClass())); } } /** * Asserts that two different references point to the same shared instance of * InstanceProfileCredentialsProvider using a descriptive assertion message. * @param provider1 provider to check * @param provider2 provider to check */ private static void assertSameInstanceProfileCredentialsProvider( AWSCredentialsProvider provider1, AWSCredentialsProvider provider2) { assertNotNull(provider1); assertInstanceOf(InstanceProfileCredentialsProvider.class, provider1); assertNotNull(provider2); assertInstanceOf(InstanceProfileCredentialsProvider.class, provider2); assertSame("Expected all usage of InstanceProfileCredentialsProvider to " + "share a singleton instance, but found unique instances.", provider1, provider2); } }