I use Spring Cloud's ResourceLoader
to access S3, e.g.:
public class S3DownUpLoader {
private final ResourceLoader resourceLoader;
@Autowired
public S3DownUpLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public String storeOnS3(String filename, byte[] data) throws IOException {
String location = "s3://" + bucket + "/" + filename;
WritableResource writeableResource = (WritableResource) this.resourceLoader.getResource(location);
FileCopyUtils.copy( data, writeableResource.getOutputStream());
return filename;
}
It works okey and I need help to test the code with Localstack/Testcontainers. I've tried following test, but it does not work - my production profile gets picked up(s3 client with localstack config is not injected):
@RunWith(SpringRunner.class)
@SpringBootTest
public class S3DownUpLoaderTest {
@ClassRule
public static LocalStackContainer localstack = new LocalStackContainer().withServices(S3);
@Autowired
S3DownUpLoader s3DownUpLoader;
@Test
public void testA() {
s3DownUpLoader.storeOnS3(...);
}
@TestConfiguration
@EnableContextResourceLoader
public static class S3Configuration {
@Primary
@Bean(destroyMethod = "shutdown")
public AmazonS3 amazonS3() {
return AmazonS3ClientBuilder
.standard()
.withEndpointConfiguration(localstack.getEndpointConfiguration(S3))
.withCredentials(localstack.getDefaultCredentialsProvider())
.build();
}
}
}
It seems the only way to provide custom amazonS3
bean for ResourceLoader
is to inject it manually. The test looks like
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = S3DownUpLoaderTest.S3Configuration.class)
public class S3DownUpLoaderTest implements ApplicationContextAware {
private static final String BUCKET_NAME = "bucket";
@ClassRule
public static LocalStackContainer localstack = new LocalStackContainer().withServices(S3);
@Autowired
S3DownUpLoader s3DownUpLoader;
@Autowired
SimpleStorageProtocolResolver resourceLoader;
@Autowired
AmazonS3 amazonS3;
@Before
public void setUp(){
amazonS3.createBucket(BUCKET_NAME);
}
@Test
public void someTestA() throws IOException {
....
}
@After
public void tearDown(){
ObjectListing object_listing = amazonS3.listObjects(QLM_BUCKET_NAME);
while (true) {
for (S3ObjectSummary summary : object_listing.getObjectSummaries()) {
amazonS3.deleteObject(BUCKET_NAME, summary.getKey());
}
// more object_listing to retrieve?
if (object_listing.isTruncated()) {
object_listing = amazonS3.listNextBatchOfObjects(object_listing);
} else {
break;
}
};
amazonS3.deleteBucket(BUCKET_NAME);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (applicationContext instanceof ConfigurableApplicationContext) {
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
configurableApplicationContext.addProtocolResolver(this.resourceLoader);
}
}
public static class S3Configuration {
@Bean
public S3DownUpLoader s3DownUpLoader(ResourceLoader resourceLoader){
return new S3DownUpLoader(resourceLoader);
}
@Bean(destroyMethod = "shutdown")
public AmazonS3 amazonS3() {
return AmazonS3ClientBuilder
.standard()
.withEndpointConfiguration(localstack.getEndpointConfiguration(S3))
.withCredentials(localstack.getDefaultCredentialsProvider())
.build();
}
@Bean
public SimpleStorageProtocolResolver resourceLoader(){
return new SimpleStorageProtocolResolver(amazonS3());
}
}