When running fake-gcs-server in a container (e.g., via Testcontainers), the IP and port are dynamic and unknown before startup. Because resumable upload operations require the server to respond with the correct Location header (the external-url), you must update the server's configuration via its internal API after the container has started.
To do this:
- Retrieve the container's host and mapped port.
- Construct the external URL (e.g.,
http://<host>:<port>). - Send a
PUT request to the /_internal/config endpoint with a JSON body containing the externalUrl key.
@Testcontainers
class FakeGcsServerTest {
@Container
static final GenericContainer<?> fakeGcs = new GenericContainer<>("fsouza/fake-gcs-server")
.withExposedPorts(4443)
.withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint(
"/bin/fake-gcs-server",
"-scheme", "http"
));
@BeforeAll
static void setUpFakeGcs() throws Exception {
String fakeGcsExternalUrl = "http://" + fakeGcs.getHost() + ":" + fakeGcs.getFirstMappedPort();
updateExternalUrlWithContainerUrl(fakeGcsExternalUrl);
storageClient = StorageOptions.newBuilder()
.setHost(fakeGcsExternalUrl)
.setProjectId("test-project")
.setCredentials(NoCredentials.getInstance())
.build()
.getService();
}
private static void updateExternalUrlWithContainerUrl(String fakeGcsExternalUrl) throws Exception {
String modifyExternalUrlRequestUri = fakeGcsExternalUrl + "/_internal/config";
String updateExternalUrlJson = "{" + "\"externalUrl\": \"" + fakeGcsExternalUrl + "\"}";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create(modifyExternalUrlRequestUri))
.header("Content-Type", "application/json")
.PUT(BodyPublishers.ofString(updateExternalUrlJson))
.build();
HttpResponse<Void> response = HttpClient.newBuilder().build()
.send(req, BodyHandlers.discarding());
if (response.statusCode() != 200) {
throw new RuntimeException(
"error updating fake-gcs-server with external url, response status code " + response.statusCode() + " != 200");
}
}
@Test
void shouldUploadFileByWriterChannel() throws IOException {
storageClient.create(BucketInfo.newBuilder("sample-bucket2").build());
WriteChannel channel = storageClient.writer(BlobInfo.newBuilder("sample-bucket2", "some_file2.txt").build());
channel.write(ByteBuffer.wrap("line1\n".getBytes()));
channel.write(ByteBuffer.wrap("line2\n".getBytes()));
channel.close();
Blob someFile2 = storageClient.get("sample-bucket2", "some_file2.txt");
String fileContent = new String(someFile2.getContent());
assertEquals("line1\nline2\n", fileContent);
}
}