diff --git a/docs/contributing.md b/docs/contributing.md index 07da7c7912..fd36ee3a55 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,4 +1,3 @@ # Contributing -Hello - +We follow the same one used by [testcontainers-java check it out](https://www.testcontainers.org/contributing/). diff --git a/docs/contributing_docs.md b/docs/contributing_docs.md index ace17016de..94d110cb4e 100644 --- a/docs/contributing_docs.md +++ b/docs/contributing_docs.md @@ -5,14 +5,10 @@ We use the [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) t In addition we use a [custom plugin](https://github.com/rnorth/mkdocs-codeinclude-plugin) for inclusion of code snippets. -We publish our documentation using Netlify. +We publish our documentation using Netlify. ## Previewing rendered content -### Using Docker locally - -The root of the project contains a `docker-compose.yml` file. Simply run `docker-compose up` and then access the docs at [http://localhost:8000](http://localhost:8000). - ### Using Python locally * Ensure that you have Python 3.6.0 or higher. diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md new file mode 100644 index 0000000000..229e2e665b --- /dev/null +++ b/docs/features/creating_container.md @@ -0,0 +1,54 @@ +# How to create a container + +When I have to describe TestContainer I say: "it is a wrapper around the docker +daemon designed for tests." + +This libraries demands all the complexity of creating and managing container to +Docker to stay focused on usability in a testing environment. + +You can use this library to run everything you can run with docker: + +* NoSQL databases or other data stores (e.g. redis, elasticsearch, mongo) +* Web servers/proxies (e.g. nginx, apache) +* Log services (e.g. logstash, kibana) +* Other services developed by your team/organization which are already dockerized + +## GenericContainer + +`testcontainers.GenericContainer` identifies the ability to spin up a single +container, you can look at it as a different way to create a `docker run` +command. + +```go +func TestNginxLatestReturn(t *testing.T) { + ctx := context.Background() + req := testcontainers.ContainerRequest{ + Image: "nginx", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForHTTP("/"), + } + nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Error(err) + } + defer nginxC.Terminate(ctx) + ip, err := nginxC.Host(ctx) + if err != nil { + t.Error(err) + } + port, err := nginxC.MappedPort(ctx, "80") + if err != nil { + t.Error(err) + } + resp, err := http.Get(fmt.Sprintf("http://%s:%s", ip, port.Port())) + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode) + } +} +``` + +This test creates an Nginx container and it validates that it returns a 200 as +StatusCode. diff --git a/docs/features/garbage_collector.md b/docs/features/garbage_collector.md new file mode 100644 index 0000000000..949266e249 --- /dev/null +++ b/docs/features/garbage_collector.md @@ -0,0 +1,43 @@ +# Garbage Collector + +Usually one test creates at least one container. At the end it means a lot of +containers running. We need to have a way to keep the CI servers reliable +removing unused containers. + +Containers can be unused because: + +1. Test is over and the container is not needed anymore. +2. Test failed, we do not need that container anymore because next build will + create new containers. + +## Terminate function + +As we saw previously there are at least two way to remove unused containers. +First one is to use the `Terminate(context.Conext)` function available when a +container is created. You can call it in your test or you use `defer` . + +!!!tip + Remember to `defer` as soon as possible so you won't forget. The best time + is as soon as you call `testcontainers.GenericContainer` but remember to + check for the `err` first. + +## Ryuk + +[https://github.com/testcontainers/moby-ryuk](ryuk) helps you to remove +containers/networks/volumes by given filter after specified delay. + +It is a project developer by TestContainer and it is used across the board for +Java, Go and any more. + +When you run one tests you will see that there is not only the containers your +tests requires running, there is another one called `ryuk`, we refers to it as +`Reaper` as well in this library. + +Based on container labels it removes resources created from testcontainers that +are running from more than 10 minutes. + +!!!tip + This feature can be disabled when creating a container + +In this way even if you do not call Terminate, something will keep your +environment clean. It will also clean itself when there is nothing left to do. diff --git a/docs/index.md b/docs/index.md index cbc48745b4..12972601da 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,3 +4,8 @@ ## About +TestContainers is popular in Java, but there are other langauges as well. This +is the Go implementation. + +The project is opensource and you can have a look at the code on +[GitHub](httsp://github.com/testcontainers/testcontainers-go), diff --git a/docs/quickstart/gotest.md b/docs/quickstart/gotest.md new file mode 100644 index 0000000000..d5b23ffad6 --- /dev/null +++ b/docs/quickstart/gotest.md @@ -0,0 +1,99 @@ +TestContainers plays well with the native `go test` framework. + +The ideal use case is for integration or end to end tests. It helps you to spin +up and manage the dependencies life cycle via Docker. + +This is way Docker has to be available for this library to work. + +## 1. Install + +We use [gomod](https://blog.golang.org/using-go-modules) and you can get it installed via: + +``` +go get github.com/testcontainers/testcontainers-go +``` + +## 2. Spin up Redis + +```go +func TestWithRedis(t *testing.T) { + ctx := context.Background() + req := testcontainers.ContainerRequest{ + Image: "redis:latest", + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + t.Error(err) + } + defer redisC.Terminate(ctx) +} +``` + +The `testcontainers.ContainerRequest` describes how the Docker container will +look like. As you ca see it recalls to a lot of concepts related to it. + +* `Image` is the docker image the container starts from. +* `ExposedPorts` lists the port that has to be exposed from the container +* `WaitingFor` is a field you can use to validate when a container is ready. It + is important to get this set because it helps to know when the container is + ready to reach any traffic. In this case we checks for the logs we know coming + from Redis, telling us that it is ready to accept requests. + +When you use `ExposedPorts` you have to image yourself using `docker run -p +`. When you do so dockerd maps the selected `` from inside the +container to a random one available on your host. + +In the previous example we expose `6379` for `tcp` traffic to the outside. This +allows Redis to be reachable from your code that runs outside the container but +it also makes parallelization possible because if you add `t.Parallel` to you +test and each of them starts a Redis container all of them will be exposed on a +different random port. + +`testcontainers.GenericContainer` creates the container. In this example we are +using `Started: true`. It means that the container function will wait for the +container to be up and running. If you set the `Start` value to `false` it won' +start. Leaving to you the decision about when to start it. + +All the container has to be removed at some point, otherwise they will run until +the host will overloaded. One of the way we have to clean after ourself is +defering the terminated function: `defer redisC.Terminate(ctx)`. + +!!!tip + Lock at [features/garbage_collector.md] to know the other way we have to + clean after ourself. + +## 3. Make your code to talk with the container + +This is just an example but usually Go applications that relay on redis are +using the [redis-go](https://github.com/go-redis/redis) client. This code gets the endpoint from the container we +just started and it configures the client. + +```go +endpoint, err := redisC.Endpoint(ctx, "") +if err != nil { + t.Error(err) +} + +client := redis.NewClient(&redis.Options{ + Addr: endpoint, +}) + +_ = client +``` + +We expose only one port, so the `Endpoint` does not need a second argument set. + +!!!tip + if you expose more than one port you an specify the one you need as second + argument + +In this case it returns: `localhost:`. + +## 3. Run the test + +You can run the test via `go test ./...` diff --git a/mkdocs.yml b/mkdocs.yml index 1e45bbe484..c25e296114 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,8 +22,14 @@ markdown_extensions: - pymdownx.snippets nav: - Home: index.md + - Quickstart: + - quickstart/gotest.md + - Features: + - features/creating_container.md + - features/garbage_collector.md - Contributing: - contributing.md - contributing_docs.md + - Getting help: getting_help.md extra: latest_version: 1.14.1