spring-bootspring-boot-testtestcontainerstestcontainers-junit5

How to combine SpringBootTest and Testcontainers with fake-gcs-server container


I am trying to write a test case for testing read/write access to a Google Cloud Bucket using Spring Boot (v2.7.5). For this I tried to use the 'Testcontainer' framework in combination with a fake Google Cloud Storage container (fake-gcs-server).

The problem is that the app does not start with this configuration. The error message is "The Application Default Credentials are not available."

I have set the '.setCredentials(NoCredentials.getInstance())' but that does not help.

@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // Share data between the test methods
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // Enable ordering of test methods
@Testcontainers
class GPSStorageTest {

    private static final String BUCKET_NAME = "BUCKET_TEST";

    private static final Integer INTERNAL_PORT = 8888;

    protected static Storage storage = null;

    // Set the GenericContainer to 'static' and the GenericContainer will be shared between test methods
    @Container
    private static final GenericContainer<?>gcsFakeContainer =
            new GenericContainer<>(DockerImageName.parse("fsouza/fake-gcs-server:latest"))
            .withCommand("-port",INTERNAL_PORT.toString(), "-scheme", "http")
            .withExposedPorts(8888)
                    .waitingFor(Wait.forHttp("/").forStatusCode(404))
            .withReuse(true);

    @BeforeAll
    public static void setup() {
        int mappedPort = gcsFakeContainer.getMappedPort(INTERNAL_PORT);
        StorageOptions storageOps = StorageOptions.newBuilder()
                .setCredentials(NoCredentials.getInstance())
                .setHost("http://" + gcsFakeContainer.getHost() + ":" + mappedPort)
                .setProjectId("TEST_LOCAL")
                .build();

        storage = storageOps.getService();
    }

    @Test
    @Order(1)
    public void testCreateBucket() {
        createBucket();
        Assertions.assertTrue(checkBucketExists());
    }

    @Test
    @Order(2)
    public void testIfFileWritten() {

        String filename = "test.txt";
        Bucket bucket = storage.get(BUCKET_NAME);
        bucket.create(filename, "Hello, World!".getBytes(UTF_8));
        Assertions.assertTrue(fileExits(filename));
    }

    private boolean fileExits(String filename) {
        return storage.get(BUCKET_NAME,filename) != null;
    }

    private void createBucket() {
        try {
            storage.create(BucketInfo.of(BUCKET_NAME));
        } catch (Exception ex) {
            System.err.println("Error creating bucket");
            ex.printStackTrace();
        }
    }

    private boolean checkBucketExists() {
        return storage.get(BUCKET_NAME, Storage.BucketGetOption.fields()) != null;
    }
}

Does anyone have any ideas on how I can get it to work?

Update I put the previous class in a small demo project to demonstrate the problem: https://github.com/benocms/de.test.testcontainers


Solution

  • I fixed the problem.

    This configuration disables the automatic Spring Boot configuration of the cloud.gcp.storage API.

    application.properties:

    spring.cloud.gcp.storage.enabled=false
    

    Update

    This configuration is also possible in the test class itself:

        @DynamicPropertySource
        static void gcsFakeProperties(DynamicPropertyRegistry registry) {
            registry.add("spring.cloud.gcp.storage.enabled",()-> false);
        }
    

    Note: The @DynamicPropertySource annotation is only available since Spring Boot >= 2.2.6.