Skip to content

Commit

Permalink
Merge pull request #2 from amirhnajafiz/1-redesign
Browse files Browse the repository at this point in the history
1 redesign
  • Loading branch information
amirhnajafiz authored Nov 20, 2022
2 parents 3f86de4 + 0813751 commit f2fd52c
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 183 deletions.
125 changes: 85 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,110 @@
Test Containers
</h1>

Example of using Test containers in Golang. Creating a **redis** cluster with
containers and test redis cluster with Golang SDK while running unit tests.
Example of using Test containers in Golang. Creating a **Nats** cluster with
containers and test nats cluster with Golang SDK while running unit tests.

## What are test-containers?

Test-containers is a package that makes it simple to create and clean up container-based
dependencies for automated _integration/smoke_ tests.

We use _test-containers_ to run our dependent services like databases in a container
hense we won't need to mock them or use real external services. This makes our uint tests more
efficient and more reliable. Let's see an example.
hence we won't need to mock them or use real external services. This makes our uint tests more
efficient and more reliable.

## Redis container
The clean, easy-to-use API enables developers
to programmatically define containers that should
be run as part of a test and clean up those
resources when the test is done.

All we need for running a redis container with ```docker-compose``` is
an image name and image version.
## Example

These data are all in ```pkg/storage/redis/container.go```.
In the following example, we are going to create a **Nats**
container and test it.

```go
const (
// redis image information
imageName = "redis"
imageTag = "latest"
)
// container build request
req := testcontainers.ContainerRequest{
Image: "nats:latest",
ExposedPorts: []string{"4222/tcp", "8222/tcp"},
Cmd: []string{
"--http_port 8222",
"--cluster nats://0.0.0.0:6222",
"--cluster_name NATS",
},
WaitingFor: wait.ForLog("Listening for client connections"),
}
```

Now we build our container with a request.
The ```testcontainers.ContainerRequest``` describes how the Docker container will look.

- ```Image``` is the Docker image the container starts from.
- ```ExposedPorts``` lists the ports to be exposed from the container.
- ```Cmd``` is the commands that will be executed when container is set.
- ```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 receive any traffic. In this case, we check for the logs we know come from Redis, telling us that it is ready to accept requests.

When you use ExposedPorts you have to imagine
yourself using ```docker run -p <port>```.
When you do so, dockerd maps the selected ```<port>``` from
inside the container to a random one available on your host.

```go
// container request
req := testcontainers.ContainerRequest{
Image: imageName + ":" + imageTag,
ExposedPorts: []string{"6379/tcp"},
WaitingFor: wait.ForLog("Ready to accept connections"),
}
// building a generic container
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
```

Now you can access container in your source codes.
```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't start,
leaving to you the decision about when to start it.

```go
ctx := context.Background()
// cleaning container after test is complete
t.Cleanup(func() {
t.Log("terminating container")

if er := container.Terminate(ctx); er != nil {
t.Errorf("failed to terminate container: :%v", er)
}
})
```

// creating a new container.
redisC, err := redis.CreateRedisContainer()
if err != nil {
t.Error(err)
All the containers must be removed
at some point, otherwise they will run until
the host is overloaded.
One of the ways we have to clean up is by deferring the terminated function:
```defer container.Terminate(ctx)```.

return
}
## Talking to container

// get container connection.
redisConnection, err := redisC.Endpoint(ctx, "")
if err != nil {
t.Error(err)
```go
// opening connection
nc, er := nats.Connect(container.URI)
if er != nil {
t.Error(fmt.Errorf("connecting to nats container failed:\n\t%v\n", er))

return
}
```

## Test

Execute redis container test with following command:

```shell
go test -v ./...
```
// async subscriber
go func() {
_, e := nc.Subscribe(natsTopic, func(m *nats.Msg) {
log.Printf("Received a message:\n\t%s\n", string(m.Data))
})
if e != nil {
t.Error(fmt.Errorf("subscribe over topic failed:\n\t%v\n", e))
}
}()

// publish over topic
if e := nc.Publish(natsTopic, []byte(natsValue)); e != nil {
t.Error(fmt.Errorf("publish over topic failed:\n\t%v\n", e))
}
```
15 changes: 10 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ module github.com/amirhnajafiz/testcontainers

go 1.19

require (
github.com/nats-io/nats.go v1.20.0
github.com/testcontainers/testcontainers-go v0.15.0
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.4 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/containerd/containerd v1.6.8 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.17+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/go-redis/redis/v9 v9.0.0-rc.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
Expand All @@ -25,15 +27,18 @@ require (
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/nats-io/nats-server/v2 v2.9.7 // indirect
github.com/nats-io/nkeys v0.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/opencontainers/runc v1.1.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/testcontainers/testcontainers-go v0.15.0 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
Expand Down
Loading

0 comments on commit f2fd52c

Please sign in to comment.