Philipp Mayer
09/04/2023, 9:59 AMdave
09/04/2023, 11:07 AMAndrew O'Hara
09/04/2023, 4:13 PMhttp4k-aws
module had an adapter you can use to route your requests in-memory. See this example, and this part in particular. If you want to route to an actual running fake server, then you can just override the client endpoint settings, as David suggested.Philipp Mayer
09/05/2023, 11:57 AMimport org.http4k.aws.AwsSdkClient
import org.http4k.client.JavaHttpClient
import org.http4k.connect.amazon.core.model.Region
import org.http4k.connect.amazon.s3.FakeS3
import org.http4k.connect.amazon.s3.createBucket
import org.http4k.connect.amazon.s3.model.BucketName
import org.http4k.core.Uri
import org.http4k.core.then
import org.http4k.filter.ClientFilters
import org.http4k.filter.debug
import org.http4k.server.SunHttp
import org.http4k.server.asServer
import software.amazon.awssdk.core.sync.RequestBody
import software.amazon.awssdk.services.s3.S3Client
import software.amazon.awssdk.services.s3.model.PutObjectRequest
//
val bucketName = BucketName.of("example-bucket")
val s3 = FakeS3().apply {
s3Client().createBucket(bucketName, Region.EU_CENTRAL_1)
}
s3.debug().asServer(SunHttp(port = 26467)).start()
val client = ClientFilters.SetBaseUriFrom(Uri.of("<http://example-bucket.s3.eu-central-1.localhost:26467>")).then(JavaHttpClient()
)
val s3Client: S3Client = S3Client.builder()
.httpClient(AwsSdkClient(client))
.region(software.amazon.awssdk.regions.Region.EU_CENTRAL_1)
.build()
val request = PutObjectRequest.builder()
.bucket(bucketName.value)
.key("this-is-a-key")
.build()
val body = RequestBody.fromString("test")
s3Client.putObject(request, body)
yields:
software.amazon.awssdk.services.s3.model.S3Exception: null (Service: S3, Status Code: 503, Request ID: null)
just posting via curl works, though:
curl --location '<http://dealer-attachments.s3.eu-central-1.localhost:26467>'
This is now rather off-topic because it’s more on the AWS sdk side, but maybe someone encountered the same issue 🙂
I guess it’s because of the dns resolution - if I point the client against <http://localhost>:...
it works, but isn’t forwarded to the right bucket.
The readme also covers that, but I don’t know how to fix it:
“In the case of a missing header (if for instance a non-http4k client attempts to push some data into it without the x-forwarded-for header, it creates a global bucket which is then used to store all of the data for these unknown requests.“Andrew O'Hara
09/05/2023, 1:28 PMAwsSdkClient
is only necessary if you want to use an in-memory server. In that case, you don't need to start FakeS3, and would just do .httpClient(AwsSdkClient(FakeS3()))
If you want to run against a fake server running with a port, you don't need to override the httpClient(...)
. Instead you should do an .endPointOverride(URI("<http://localhost>:${server.port()}"))
on the client builder. You don't need to override the server's port; it will use any available one.
I've updated the example code to show both methods. Here's how to do the latter.Andrew O'Hara
09/05/2023, 2:02 PMJavaHttpClient
could be a novel way to eliminate the heavyweight apache client. I don't normally bother with that outside lambdas.Philipp Mayer
09/05/2023, 2:06 PM.endPointOverride
already, resulting in:
.endpointOverride(URI("<http://localhost:26467>"))
to`Caused by: java.net.UnknownHostException: dealer-attachments.localhost`
.endpointOverride(URI("<http://s3.eu-central-1.localhost:26467>"))
to Caused by: java.net.UnknownHostException: dealer-attachments.s3.eu-central-1.localhost
etc. I can’t pin point it for now, but I still have the gut feeling around DNS issues.
Again, this is what I want to end up with basically: curl --location --request PUT '<http://dealer-attachments.s3.eu-central-1.localhost:26467/test1234>'
dave
09/05/2023, 2:07 PMAwsHttpClient(SetHostFrom(Uri.of('<http://localhost:80123>")).then(JavaHttpClient))
Philipp Mayer
09/05/2023, 2:08 PMPhilipp Mayer
09/05/2023, 2:17 PMdebug().asServer(SunHttp(port = 26467)).start()
to show that it’s not reaching the actual endpoint)
val client = ClientFilters.SetBaseUriFrom(Uri.of("<http://localhost:26467>"))
.then(JavaHttpClient())
Will log the request to FakeS3, but it’s targeting the incorrect endpoint.Andrew O'Hara
09/05/2023, 2:26 PMPhilipp Mayer
09/05/2023, 2:26 PMPhilipp Mayer
09/05/2023, 2:27 PMAndrew O'Hara
09/05/2023, 5:29 PMdave
09/05/2023, 5:39 PMPhilipp Mayer
09/05/2023, 8:21 PMIs there a particular reason you want to test against a running server, and not in-memory?I’m introducing tests to a typical spring boot code base and want to use it in an E2E context - the local server version is better fitting there and easier to grasp for the team (which is new to Kotlin and thorough testing overall). Hope that makes sense. 🙂
Philipp Mayer
09/07/2023, 11:05 AMAndrew O'Hara
09/07/2023, 11:31 AMdave
09/07/2023, 11:53 AMAndrew O'Hara
09/07/2023, 12:11 PMFakeS3
in port mode, which I guess is a bit of the latter. 🤔Philipp Mayer
09/07/2023, 11:47 PMPhilipp Mayer
09/07/2023, 11:48 PMAndrew O'Hara
09/08/2023, 2:35 AMAndrew O'Hara
09/08/2023, 2:36 AMPhilipp Mayer
09/08/2023, 6:40 AMAndrew O'Hara
09/20/2023, 1:11 AMFakeS3
as a server, it works as-is with the http4k-connect client. In order to use the official V2 SDK, David's workaround worked for me. I'm adding this as an example to the examples repo.
val http= ClientFilters.SetHostFrom(FakeS3::class.defaultLocalUri).then(JavaHttpClient())
val client = S3Client.builder()
.httpClient(AwsSdkClient(http))
.credentialsProvider { AwsBasicCredentials.create("key_id", "secret_key") }
.build()
https://github.com/http4k/http4k-connect-examples/pull/49Philipp Mayer
10/03/2023, 7:19 PM