testcontainers / testcontainers-dotnet

A library to support tests with throwaway instances of Docker containers for all compatible .NET Standard versions.
https://dotnet.testcontainers.org
MIT License
3.73k stars 262 forks source link

feat: Add Google Cloud Storage API (fake-gcs-server) module #1023

Closed KSemenenko closed 10 months ago

KSemenenko commented 10 months ago

What does this PR do?

Add Google Cloud Storage to testcontainer

Why is it important?

Now testcontainer will have Azure, AWS and GCP for tests

Related issues

netlify[bot] commented 10 months ago

Deploy Preview for testcontainers-dotnet ready!

Name Link
Latest commit 5bdc1d79dd39691252b41df30985adefda5eb01b
Latest deploy log https://app.netlify.com/sites/testcontainers-dotnet/deploys/653027a80504640008e0569b
Deploy Preview https://deploy-preview-1023--testcontainers-dotnet.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

KSemenenko commented 10 months ago

there is one problem

    return base.Init()
            .WithImage(GCSImage)
            .WithPortBinding(GCSPort, newPort)
            .WithCommand("-scheme", "http")
            .WithCommand("-backend", "memory")
            .WithCommand("-external-url", $"http://localhost:{newPort}")
            .WithCommand("-port", newPort.ToString())
            .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(request =>
                request.ForPath("/").ForPort(newPort).ForStatusCode(HttpStatusCode.NotFound)));

I have to pass acutal port into -external-url paramenter. how can I do this?

KSemenenko commented 10 months ago

this is how docker config shoud looks like https://github.com/fsouza/fake-gcs-server/blob/main/examples/dotnet/docker-compose.yaml

HofmeisterAn commented 10 months ago

I have to pass acutal port into -external-url paramenter.

Hi ๐Ÿ‘‹ do you mean the actual random assigned host port? It is not very common that a services running inside a container requires it, but you can configure something similar like Kafka and utilize the WithStartupCallback builder member:

https://github.com/testcontainers/testcontainers-dotnet/blob/44a1d3a9418f22c1761de7e8d64e4f7fb9d1c7f8/src/Testcontainers.Kafka/KafkaBuilder.cs#L65-L66

Theย WithStartupCallback builder member prepares a shell script and copies it during the start to the container. The callback has access to the random assigned host port (see L:82):

https://github.com/testcontainers/testcontainers-dotnet/blob/44a1d3a9418f22c1761de7e8d64e4f7fb9d1c7f8/src/Testcontainers.Kafka/KafkaBuilder.cs#L82-L87

KSemenenko commented 10 months ago

Yeah, itโ€™s because of container, I have no idea why. But super thanks a lot I will try!

KSemenenko commented 10 months ago

@HofmeisterAn the problem is I have to pass port number into paramter

so for code .WithPortBinding(GCSPort, true) I have to get somehow this random port and pass it as RandomPort .WithCommand("-external-url", $"http://localhost:{RandomPort}") in parameter. so this is the issue

KSemenenko commented 10 months ago

if I do like hits

return base.Init()
            .WithImage(GCSImage)
            .WithPortBinding(GCSPort, GCSPort)
            .WithCommand("-scheme", "http")
            .WithCommand("-backend", "memory")
            .WithCommand("-external-url", $"http://localhost:{GCSPort}")
            .WithCommand("-port", $"{GCSPort}")
            .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(request =>
                request.ForPath("/").ForPort(GCSPort).ForStatusCode(HttpStatusCode.NotFound)));

then all is fine, and it works. but it's not possible to run several containers at the same time

HofmeisterAn commented 10 months ago

@HofmeisterAn the problem is I have to pass port number into paramter

As mentioned in my previous comment, you need a configuration similar to Kafka:

  1. Override the entrypoint that executes a shell.
  2. Override the command and set a command that waits until the startup script is written and then executes it.
  3. Prepare the startup script in WithStartupCallback, where you have access to the random assigned host port.
  4. Finally, copy the prepared startup script to the container. As soon as it is written, the overridden entrypoint and respective command will execute it, starting the service inside the container.
KSemenenko commented 10 months ago

ok if I do [Collection("Google")] for collections thet all is fine

HofmeisterAn commented 10 months ago

ok if I do [Collection("Google")] for collections thet all is fine

I am sorry, I do not understand. Modules must work with random assigned host ports; we cannot accept the pull request using fixed host ports. You can find further details in our best practices.

KSemenenko commented 10 months ago

@Hofmeisteran that was my random thoughts, anyway thanks for your help, now it works fine =) also I maked right tests.

KSemenenko commented 10 months ago

@HofmeisterAn the problem is I have to pass port number into paramter

As mentioned in my previous comment, you need a configuration similar to Kafka:

  1. Override the entrypoint that executes a shell.
  2. Override the command and set a command that waits until the startup script is written and then executes it.
  3. Prepare the startup script in WithStartupCallback, where you have access to the random assigned host port.
  4. Finally, copy the prepared startup script to the container. As soon as it is written, the overridden entrypoint and respective command will execute it, starting the service inside the container.

This is really amazing suggeest! thanks a lot!

KSemenenko commented 10 months ago

Now itโ€™s ready for review

KSemenenko commented 10 months ago

fixed, but with some reason one pipline is borken, I did that?

KSemenenko commented 10 months ago

aH I see

KSemenenko commented 10 months ago

@HofmeisterAn thansks a lot! This is super cool finding!

KSemenenko commented 10 months ago

@HofmeisterAn Hi! Thanks for merging this request! By the way, when will his package be available?

HofmeisterAn commented 10 months ago

I have not planned a release yet. I want to make some minor changes in the next days, but I need a short break as I am feeling drained.

KSemenenko commented 10 months ago

Sure! I'm just checking to see when I can throw out my old implementation and replace it with a nice nuget package =)