From ad31c406df92a3560329018732e29dee4cbfbc63 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 20:29:33 -0700 Subject: [PATCH 01/13] cleaned up readme --- README.md | 63 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index c175bf5008..0d8aa8cd36 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,11 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/testcontainers/testcontainers-go)](https://goreportcard.com/report/github.com/testcontainers/testcontainers-go) [![GoDoc Reference](https://camo.githubusercontent.com/8609cfcb531fa0f5598a3d4353596fae9336cce3/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f79616e6777656e6d61692f686f772d746f2d6164642d62616467652d696e2d6769746875622d726561646d653f7374617475732e737667)](https://pkg.go.dev/github.com/testcontainers/testcontainers-go) -When I was working on a Zipkin PR I discovered a nice Java library called -[Testcontainers](https://www.testcontainers.org/). +Testcontainers-Go is a package that makes it simple to set up container-based dependencies for automated +integration/smoke tests. 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. -It provides an easy and clean API over the go docker sdk to run, terminate and -connect to containers in your tests. - -I found myself comfortable programmatically writing the containers I need to run -an integration/smoke tests. So I started porting this library in Go. - -This is an example: +Here's an example of a test that spins up an NGINX container and executes an HTTP request against it: ```go package main @@ -26,44 +21,62 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -func TestNginxLatestReturn(t *testing.T) { - ctx := context.Background() +type nginxContainer struct { + testcontainer.Container + URI string +} + +func setupNginx(ctx context.Context) { req := testcontainers.ContainerRequest{ Image: "nginx", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/"), } - nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, }) if err != nil { - t.Fatal(err) + return nil, err } - defer nginxC.Terminate(ctx) - ip, err := nginxC.Host(ctx) + + ip, err := container.Host(ctx) if err != nil { - t.Fatal(err) + return nil, err } - port, err := nginxC.MappedPort(ctx, "80") + + mappedPort, err := container.MappedPort(ctx, "80") if err != nil { + return nil, err + } + + uri := fmt.Sprintf("http://%s:%s", ip, mappedPort.Port()) + + return &nginxContainer{Container: container, URI: uri}, nil +} + +func TestNginxLatestReturn(t *testing.T) { + ctx := context.Background() + + nginxC, err := setupNginx(ctx) + if (err != nil) { t.Fatal(err) } - resp, err := http.Get(fmt.Sprintf("http://%s:%s", ip, port.Port())) + + // Clean up the container after the test is complete + defer nginxC.Terminate(ctx) + + resp, err := http.Get(nginxC.URI) if resp.StatusCode != http.StatusOK { t.Fatalf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode) } } ``` -This is a simple example, you can create one container in my case using the -`nginx` image. You can get its IP `ip, err := nginxC.GetContainerIpAddress(ctx)` and you -can use it to make a GET: `resp, err := http.Get(fmt.Sprintf("http://%s", ip))` -To clean your environment you can defer the container termination `defer -nginxC.Terminate(ctx, t)`. `t` is `*testing.T` and it is used to notify is the -`defer` failed marking the test as failed. +Cleaning up your environment after test completion should be accomplished by deferring the container termination, e.g +`defer nginxC.Terminate(ctx)`. Ryuk (Reaper) is also enabled by default to help clean up. ## Documentation -The documentation lives in [./docs](./docs) and it is rendered at +More information about TestContainers-Go can be found in [./docs](./docs), which rendered at [golang.testcontainers.org](https://golang.testcontainers.org). From 25fc53e2585109a09188824c41b7c90b09716c93 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 21:50:03 -0700 Subject: [PATCH 02/13] added examples directory per #112 --- .gitignore | 1 + README.md | 14 ++-- docs/examples/cockroachdb.md | 142 +++++++++++++++++++++++++++++++++++ docs/examples/nginx.md | 69 +++++++++++++++++ docs/examples/redis.md | 97 ++++++++++++++++++++++++ docs/modules.md | 26 ------- mkdocs.yml | 5 +- 7 files changed, 322 insertions(+), 32 deletions(-) create mode 100644 docs/examples/cockroachdb.md create mode 100644 docs/examples/nginx.md create mode 100644 docs/examples/redis.md delete mode 100644 docs/modules.md diff --git a/.gitignore b/.gitignore index 5f986a390d..9c2bea3d5d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ site/ src/mkdocs-codeinclude-plugin src/pip-delete-this-directory.txt .idea/ +.DS_Store cover.txt diff --git a/README.md b/README.md index 0d8aa8cd36..cfefeb14f9 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ import ( ) type nginxContainer struct { - testcontainer.Container + testcontainers.Container URI string } -func setupNginx(ctx context.Context) { +func setupNginx(ctx context.Context) (*nginxContainer, error) { req := testcontainers.ContainerRequest{ Image: "nginx", ExposedPorts: []string{"80/tcp"}, @@ -55,11 +55,15 @@ func setupNginx(ctx context.Context) { return &nginxContainer{Container: container, URI: uri}, nil } -func TestNginxLatestReturn(t *testing.T) { +func TestIntegrationNginxLatestReturn(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + ctx := context.Background() nginxC, err := setupNginx(ctx) - if (err != nil) { + if err != nil { t.Fatal(err) } @@ -74,7 +78,7 @@ func TestNginxLatestReturn(t *testing.T) { ``` Cleaning up your environment after test completion should be accomplished by deferring the container termination, e.g -`defer nginxC.Terminate(ctx)`. Ryuk (Reaper) is also enabled by default to help clean up. +`defer nginxC.Terminate(ctx)`. Reaper (Ryuk) is also enabled by default to help clean up. ## Documentation diff --git a/docs/examples/cockroachdb.md b/docs/examples/cockroachdb.md new file mode 100644 index 0000000000..802999de81 --- /dev/null +++ b/docs/examples/cockroachdb.md @@ -0,0 +1,142 @@ +# CockroachDB Container Example +```go +package main + +import ( + "context" + "database/sql" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + _ "github.com/jackc/pgx/v4/stdlib" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +// Task represents a unit of work to complete. We're going to be using this in our example as a way to organize data +// that is being manipulated in the database. +type task struct { + ID string `json:"id"` + Description string `json:"description"` + DateDue *time.Time `json:"date_due,string"` + DateCreated time.Time `json:"date_created,string"` + DateUpdated time.Time `json:"date_updated"` +} + +type cockroachDBContainer struct { + testcontainers.Container + URI string +} + +func setupCockroachDB(ctx context.Context) (*cockroachDBContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "cockroachdb/cockroach:latest-v21.1", + ExposedPorts: []string{"26257/tcp", "8080/tcp"}, + WaitingFor: wait.ForHTTP("/health").WithPort("8080"), + Cmd: []string{"start-single-node", "--insecure"}, + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + mappedPort, err := container.MappedPort(ctx, "26257") + if err != nil { + return nil, err + } + + hostIP, err := container.Host(ctx) + if err != nil { + return nil, err + } + + uri := fmt.Sprintf("postgres://root@%s:%s", hostIP, mappedPort.Port()) + + return &cockroachDBContainer{Container: container, URI: uri}, nil +} + +func initCockroachDB(ctx context.Context, db sql.DB) error { + // Actual SQL for initializing the database should probably live elsewhere; this is just an example + const query = `CREATE DATABASE projectmanagement; + CREATE TABLE projectmanagement.task( + id uuid primary key not null, + description varchar(255) not null, + date_due timestamp with time zone, + date_created timestamp with time zone not null, + date_updated timestamp with time zone not null);` + _, err := db.ExecContext(ctx, query) + + return err +} + +func truncateCockroachDB(ctx context.Context, db sql.DB) error { + const query = `TRUNCATE projectmanagement.task` + _, err := db.ExecContext(ctx, query) + return err +} + +func TestIntegrationDBInsertSelect(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test") + } + + ctx := context.Background() + + cdbContainer, err := setupCockroachDB(ctx) + if err != nil { + t.Fatal(err) + } + defer cdbContainer.Terminate(ctx) + + db, err := sql.Open("pgx", cdbContainer.URI+"/projectmanagement") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + err = initCockroachDB(ctx, *db) + if err != nil { + t.Fatal(err) + } + defer truncateCockroachDB(ctx, *db) + + now := time.Now() + + // Insert data + tsk := task{ID: uuid.NewString(), Description: "Update resumé", DateCreated: now, DateUpdated: now} + const insertQuery = `insert into "task" (id, description, date_due, date_created, date_updated) + values ($1, $2, $3, $4, $5)` + _, err = db.ExecContext( + ctx, + insertQuery, + tsk.ID, + tsk.Description, + tsk.DateDue, + tsk.DateCreated, + tsk.DateUpdated) + if err != nil { + t.Fatal(err) + } + + // Select data + savedTsk := task{ID: tsk.ID} + const findQuery = `select description, date_due, date_created, date_updated + from task + where id = $1` + row := db.QueryRowContext(ctx, findQuery, tsk.ID) + err = row.Scan(&savedTsk.Description, &savedTsk.DateDue, &savedTsk.DateCreated, &savedTsk.DateUpdated) + if err != nil { + t.Fatal(err) + } + + if !cmp.Equal(tsk, savedTsk) { + t.Fatalf("Saved task is not the same:\n%s", cmp.Diff(tsk, savedTsk)) + } +} +``` diff --git a/docs/examples/nginx.md b/docs/examples/nginx.md new file mode 100644 index 0000000000..27f21e0c00 --- /dev/null +++ b/docs/examples/nginx.md @@ -0,0 +1,69 @@ +# NGINX Container Example +```go +package main + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +type nginxContainer struct { + testcontainers.Container + URI string +} + +func setupNginx(ctx context.Context) (*nginxContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "nginx", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForHTTP("/"), + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + ip, err := container.Host(ctx) + if err != nil { + return nil, err + } + + mappedPort, err := container.MappedPort(ctx, "80") + if err != nil { + return nil, err + } + + uri := fmt.Sprintf("http://%s:%s", ip, mappedPort.Port()) + + return &nginxContainer{Container: container, URI: uri}, nil +} + +func TestIntegrationNginxLatestReturn(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ctx := context.Background() + + nginxC, err := setupNginx(ctx) + if err != nil { + t.Fatal(err) + } + + // Clean up the container after the test is complete + defer nginxC.Terminate(ctx) + + resp, err := http.Get(nginxC.URI) + if resp.StatusCode != http.StatusOK { + t.Fatalf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode) + } +} +``` diff --git a/docs/examples/redis.md b/docs/examples/redis.md new file mode 100644 index 0000000000..7a93024b74 --- /dev/null +++ b/docs/examples/redis.md @@ -0,0 +1,97 @@ +# Redis Container Example +```go +package main + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/google/uuid" + _ "github.com/jackc/pgx/v4/stdlib" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + + "github.com/go-redis/redis/v8" +) + +type redisContainer struct { + testcontainers.Container + URI string +} + +func setupRedis(ctx context.Context) (*redisContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "redis:6", + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("* Ready to accept connections"), + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + mappedPort, err := container.MappedPort(ctx, "6379") + if err != nil { + return nil, err + } + + hostIP, err := container.Host(ctx) + if err != nil { + return nil, err + } + + uri := fmt.Sprintf("redis://%s:%s", hostIP, mappedPort.Port()) + + return &redisContainer{Container: container, URI: uri}, nil +} + +func flushRedis(ctx context.Context, client redis.Client) error { + return client.FlushAll(ctx).Err() +} + +func TestIntegrationSetGet(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test") + } + + ctx := context.Background() + + redisContainer, err := setupRedis(ctx) + if err != nil { + t.Fatal(err) + } + defer redisContainer.Terminate(ctx) + + // You'd likely want to wrap your Redis package of choice in an interface to aid in unit testing and limit lock-in + // throughtout your codebase but that's out of scope for this example + options, err := redis.ParseURL(redisContainer.URI) + if err != nil { + t.Fatal(err) + } + client := redis.NewClient(options) + defer flushRedis(ctx, *client) + + // Set data + key := fmt.Sprintf("{user.%s}.favoritefood", uuid.NewString()) + value := "Cabbage Biscuits" + ttl, _ := time.ParseDuration("2h") + err = client.Set(ctx, key, value, ttl).Err() + if err != nil { + t.Fatal(err) + } + + // Get data + savedValue, err := client.Get(ctx, key).Result() + if err != nil { + t.Fatal(err) + } + if savedValue != value { + t.Fatalf("Expected value %s. Got %s.", savedValue, value) + } +} +``` diff --git a/docs/modules.md b/docs/modules.md deleted file mode 100644 index 615ea85893..0000000000 --- a/docs/modules.md +++ /dev/null @@ -1,26 +0,0 @@ -TestContainers Java has the concept of -[modules](https://www.testcontainers.org/modules/nginx/). - -Those modules are reusable and pre-defined Container for popular projects. - -I don't think we are ready to do the same for Go just yet. I proposed a similar -concept called `canned`, mainly to avoid misunderstanding with [Go -modules](https://blog.golang.org/using-go-modules). - -* [Canned postgres #98](https://github.com/testcontainers/testcontainers-go/pull/98) -* [Canned minio #105](https://github.com/testcontainers/testcontainers-go/pull/105) -* [Canned MongoDB #102](https://github.com/testcontainers/testcontainers-go/pull/102) - -Submodules in Go are not easy to maintain today and I want to keep -testcontainers dependencies under control and the project light. If we start -merging modules as part of the main repository we will get one dependency at -least for each of them. This will blow up quickly adding overheard to the -maintainers of this project as well. - -## Share your modules - -I know it is important to share code because it makes a project battle tested. -You can create your own modules and you can list them here, in this way other -users will be able to import and reuse your work and experience in the meantime -that we figure out a better solution based as well on how many modules we will -get. diff --git a/mkdocs.yml b/mkdocs.yml index 5936db4863..3b29c16cbb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -31,7 +31,10 @@ nav: - features/docker_compose.md - features/follow_logs.md - features/override_container_command.md - - Modules: modules.md + - Examples: + - examples/cockroachdb.md + - examples/nginx.md + - examples/redis.md - Contributing: - contributing.md - contributing_docs.md From 10d4959abadc8170ff962872cd94a011a144f84e Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:13:06 -0700 Subject: [PATCH 03/13] minor update to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cfefeb14f9..49dbc39ca2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/testcontainers/testcontainers-go)](https://goreportcard.com/report/github.com/testcontainers/testcontainers-go) [![GoDoc Reference](https://camo.githubusercontent.com/8609cfcb531fa0f5598a3d4353596fae9336cce3/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f79616e6777656e6d61692f686f772d746f2d6164642d62616467652d696e2d6769746875622d726561646d653f7374617475732e737667)](https://pkg.go.dev/github.com/testcontainers/testcontainers-go) -Testcontainers-Go is a package that makes it simple to set up container-based dependencies for automated +Testcontainers-Go is a Go package that makes it simple to set up container-based dependencies for automated integration/smoke tests. 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. From 18b4534c0ae2dbe69c0f1c6133a42e454b9c56ed Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:34:43 -0700 Subject: [PATCH 04/13] formatting and fixes to create container docs --- README.md | 8 +-- docs/examples/cockroachdb.md | 1 + docs/examples/nginx.md | 1 + docs/examples/redis.md | 1 + docs/features/creating_container.md | 85 +++++++++++++++++++---------- 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 49dbc39ca2..415d18e4c5 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/testcontainers/testcontainers-go)](https://goreportcard.com/report/github.com/testcontainers/testcontainers-go) [![GoDoc Reference](https://camo.githubusercontent.com/8609cfcb531fa0f5598a3d4353596fae9336cce3/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f79616e6777656e6d61692f686f772d746f2d6164642d62616467652d696e2d6769746875622d726561646d653f7374617475732e737667)](https://pkg.go.dev/github.com/testcontainers/testcontainers-go) -Testcontainers-Go is a Go package that makes it simple to set up container-based dependencies for automated -integration/smoke tests. 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. +Testcontainers-Go is a Go package that makes it simple to create and clean up container-based dependencies for +automated integration/smoke tests. 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. -Here's an example of a test that spins up an NGINX container and executes an HTTP request against it: +Here's an example of a test that spins up an NGINX container validates that it returns 200 for the status code: ```go package main diff --git a/docs/examples/cockroachdb.md b/docs/examples/cockroachdb.md index 802999de81..c8550816a6 100644 --- a/docs/examples/cockroachdb.md +++ b/docs/examples/cockroachdb.md @@ -1,4 +1,5 @@ # CockroachDB Container Example + ```go package main diff --git a/docs/examples/nginx.md b/docs/examples/nginx.md index 27f21e0c00..237b3fab14 100644 --- a/docs/examples/nginx.md +++ b/docs/examples/nginx.md @@ -1,4 +1,5 @@ # NGINX Container Example + ```go package main diff --git a/docs/examples/redis.md b/docs/examples/redis.md index 7a93024b74..9d460be3fe 100644 --- a/docs/examples/redis.md +++ b/docs/examples/redis.md @@ -1,4 +1,5 @@ # Redis Container Example + ```go package main diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 229e2e665b..3dc106ae40 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -1,54 +1,83 @@ # 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) +Testcontainers are a wrapper around the Docker daemon designed for tests. Anything you can run in Docker, you can spin +up with Testcontainers and integrate into your tests: +* NoSQL databases or other data stores (e.g. Redis, ElasticSearch, MongoDB) +* 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. +`testcontainers.GenericContainer` defines the container that should be run, similar to the `docker run` command. + +The following test creates an NGINX container and validates that it returns 200 for the status code: ```go -func TestNginxLatestReturn(t *testing.T) { - ctx := context.Background() +package main + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +type nginxContainer struct { + testcontainers.Container + URI string +} + +func setupNginx(ctx context.Context) (*nginxContainer, error) { req := testcontainers.ContainerRequest{ Image: "nginx", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/"), } - nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, }) if err != nil { - t.Error(err) + return nil, err } - defer nginxC.Terminate(ctx) - ip, err := nginxC.Host(ctx) + + ip, err := container.Host(ctx) if err != nil { - t.Error(err) + return nil, err } - port, err := nginxC.MappedPort(ctx, "80") + + mappedPort, err := container.MappedPort(ctx, "80") if err != nil { - t.Error(err) + return nil, err } - resp, err := http.Get(fmt.Sprintf("http://%s:%s", ip, port.Port())) + + uri := fmt.Sprintf("http://%s:%s", ip, mappedPort.Port()) + + return &nginxContainer{Container: container, URI: uri}, nil +} + +func TestIntegrationNginxLatestReturn(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ctx := context.Background() + + nginxC, err := setupNginx(ctx) + if err != nil { + t.Fatal(err) + } + + // Clean up the container after the test is complete + defer nginxC.Terminate(ctx) + + resp, err := http.Get(nginxC.URI) if resp.StatusCode != http.StatusOK { - t.Errorf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode) + t.Fatalf("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. From f23b4f7f4802abbd47a01d3a0e69b257300c2355 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:35:42 -0700 Subject: [PATCH 05/13] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 415d18e4c5..52e1eae300 100644 --- a/README.md +++ b/README.md @@ -82,5 +82,5 @@ Cleaning up your environment after test completion should be accomplished by def ## Documentation -More information about TestContainers-Go can be found in [./docs](./docs), which rendered at +More information about TestContainers-Go can be found in [./docs](./docs), which is rendered at [golang.testcontainers.org](https://golang.testcontainers.org). From 3d6fd1cbc71492f4eada72ef90476d19b1b702a3 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:39:56 -0700 Subject: [PATCH 06/13] updated headings --- docs/examples/cockroachdb.md | 2 +- docs/examples/nginx.md | 2 +- docs/examples/redis.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/examples/cockroachdb.md b/docs/examples/cockroachdb.md index c8550816a6..353deed602 100644 --- a/docs/examples/cockroachdb.md +++ b/docs/examples/cockroachdb.md @@ -1,4 +1,4 @@ -# CockroachDB Container Example +# CockroachDB ```go package main diff --git a/docs/examples/nginx.md b/docs/examples/nginx.md index 237b3fab14..59c2cd8985 100644 --- a/docs/examples/nginx.md +++ b/docs/examples/nginx.md @@ -1,4 +1,4 @@ -# NGINX Container Example +# NGINX ```go package main diff --git a/docs/examples/redis.md b/docs/examples/redis.md index 9d460be3fe..789eb2ca14 100644 --- a/docs/examples/redis.md +++ b/docs/examples/redis.md @@ -1,4 +1,4 @@ -# Redis Container Example +# Redis ```go package main From 552e00cac15dbf70f84984d2c188ed867b28b021 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:46:39 -0700 Subject: [PATCH 07/13] updated comments so that they fit better in the code pane --- docs/examples/cockroachdb.md | 7 ++++--- docs/examples/redis.md | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/examples/cockroachdb.md b/docs/examples/cockroachdb.md index 353deed602..7700bbd75a 100644 --- a/docs/examples/cockroachdb.md +++ b/docs/examples/cockroachdb.md @@ -17,8 +17,9 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -// Task represents a unit of work to complete. We're going to be using this in our example as a way to organize data -// that is being manipulated in the database. +// Task represents a unit of work to complete. We're going to be using this in +// our example as a way to organize data that is being manipulated in +// the database. type task struct { ID string `json:"id"` Description string `json:"description"` @@ -63,7 +64,7 @@ func setupCockroachDB(ctx context.Context) (*cockroachDBContainer, error) { } func initCockroachDB(ctx context.Context, db sql.DB) error { - // Actual SQL for initializing the database should probably live elsewhere; this is just an example + // Actual SQL for initializing the database should probably live elsewhere const query = `CREATE DATABASE projectmanagement; CREATE TABLE projectmanagement.task( id uuid primary key not null, diff --git a/docs/examples/redis.md b/docs/examples/redis.md index 789eb2ca14..7085d572bc 100644 --- a/docs/examples/redis.md +++ b/docs/examples/redis.md @@ -68,8 +68,9 @@ func TestIntegrationSetGet(t *testing.T) { } defer redisContainer.Terminate(ctx) - // You'd likely want to wrap your Redis package of choice in an interface to aid in unit testing and limit lock-in - // throughtout your codebase but that's out of scope for this example + // You will likely want to wrap your Redis package of choice in an + // interface to aid in unit testing and limit lock-in throughtout your + // codebase but that's out of scope for this example options, err := redis.ParseURL(redisContainer.URI) if err != nil { t.Fatal(err) From 5e143ccb5d1fbce3c04de232438d4362b9c621ad Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:53:15 -0700 Subject: [PATCH 08/13] improved import order for redis example after running through the formatter --- docs/examples/redis.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/examples/redis.md b/docs/examples/redis.md index 7085d572bc..290fba3a40 100644 --- a/docs/examples/redis.md +++ b/docs/examples/redis.md @@ -9,12 +9,11 @@ import ( "testing" "time" + "github.com/go-redis/redis/v8" "github.com/google/uuid" _ "github.com/jackc/pgx/v4/stdlib" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" - - "github.com/go-redis/redis/v8" ) type redisContainer struct { @@ -69,8 +68,8 @@ func TestIntegrationSetGet(t *testing.T) { defer redisContainer.Terminate(ctx) // You will likely want to wrap your Redis package of choice in an - // interface to aid in unit testing and limit lock-in throughtout your - // codebase but that's out of scope for this example + // interface to aid in unit testing and limit lock-in throughtout your + // codebase but that's out of scope for this example options, err := redis.ParseURL(redisContainer.URI) if err != nil { t.Fatal(err) From 8a1e71ed4dcfd5eec40473d0a91a51578b1680a3 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 22:55:11 -0700 Subject: [PATCH 09/13] switched to em dash --- docs/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index 2ec8e9cb94..e509eb0bff 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,4 +1,4 @@ # Contributing -We follow the same guidelines used by testcontainers-java - please [check them +We follow the same guidelines used by testcontainers-java -- please [check them out](https://www.testcontainers.org/contributing/). From c58a8d80254c3cf3fc4cde4cabcbcb8c1fce8206 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 23:02:01 -0700 Subject: [PATCH 10/13] updated index --- docs/index.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/index.md b/docs/index.md index cf096dbb36..c9729ab985 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,17 +4,18 @@ ## About -TestContainers is popular in Java, but there are other languages as well. This -is the Go implementation. +Testcontainers-Go is a Go package that makes it simple to create and clean up container-based dependencies for +automated integration/smoke tests. 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. -The project is opensource and you can have a look at the code on +This project is opensource and you can have a look at the code on [GitHub](https://github.com/testcontainers/testcontainers-go). ## GoDoc -Inline documentation and docs where the code live is crucial for us. Go has a -nice support for them and we use Examples as well. Check it out -[pkg.go.dev/github.com/testcontainers/testcontainers-go](https://pkg.go.dev/github.com/testcontainers/testcontainers-go?tab=doc). +Inline documentation and docs where the code live is crucial for us. Go has nice support for them and we provide +examples as well. Check it out at +[pkg.go.dev/github.com/testcontainers/testcontainers-go](https://pkg.go.dev/github.com/testcontainers/testcontainers-go). ## License @@ -22,6 +23,5 @@ See [LICENSE](https://github.com/testcontainers/testcontainers-go/blob/master/LI ## Copyright -Copyright (c) 2018-2020 Gianluca Arbezzano and other authors. -Checkout our [lovely -contributors](https://github.com/testcontainers/testcontainers-go/graphs/contributors). +Copyright (c) 2018-2021 Gianluca Arbezzano and other authors. Check out our +[lovely contributors](https://github.com/testcontainers/testcontainers-go/graphs/contributors). From ab5d09a7803dd1697dd76e8e5c59dd9110d07ba4 Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 23:08:57 -0700 Subject: [PATCH 11/13] trigger workflows From 223e7b67d5ee7652a2d5f44488916aec9a99e61c Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Fri, 10 Sep 2021 23:24:03 -0700 Subject: [PATCH 12/13] made a pass on garbage collector docs --- docs/features/garbage_collector.md | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/features/garbage_collector.md b/docs/features/garbage_collector.md index 1ffaa4051d..4d37c82157 100644 --- a/docs/features/garbage_collector.md +++ b/docs/features/garbage_collector.md @@ -1,8 +1,8 @@ # 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. +Typically, an integration test creates one or more containers. This can mean a +lot of containers running by the time everything is done. We need to have a way +to clean up after ourselves to keep our machines running smoothly. Containers can be unused because: @@ -13,8 +13,9 @@ Containers can be unused because: ## Terminate function As we saw previously there are at least two ways to remove unused containers. -The 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` . +The primary method is to use the `Terminate(context.Conext)` function that is +available when a container is created. Use `defer` to ensure that it is called +on test completion. !!!tip @@ -24,22 +25,21 @@ container is created. You can call it in your test or you use `defer` . ## Ryuk -[https://github.com/testcontainers/moby-ryuk](ryuk) helps you to remove -containers/networks/volumes by given filter after specified delay. +[https://github.com/testcontainers/moby-ryuk](Ryuk) (also referred to as +`Reaper` in this package) removes containers/networks/volumes created by +Testcontainers-Go after a specified delay. It is a project developed by the +TestContainers organization and is used across the board for for many of the +different language implementations. -It is a project developed by TestContainers, and it is used across the board for -Java, Go and any more. - -When you run one test, you will see that there is not only the containers your -tests requires running, there is another one called `ryuk`. We refer to it as -`Reaper` as well in this library. - -Based on container labels it removes resources created from testcontainers that -are running for more than 10 seconds. +When you run one test, you will see an additional container called `ryuk` +alongside all of the containers that were specified in your test. It relies on +container labels to determine which resources were created by the package +to determine the entities that are safe to remove. If a container is running +for more than 10 seconds, it will be killed. !!!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. +Even if you do not call Terminate, Ryuk ensures that the environment will be +kept clean and even cleans itself when there is nothing left to do. From cf7972574e098263387111aac9e228ad16a4e22e Mon Sep 17 00:00:00 2001 From: Jared Petersen Date: Sat, 2 Oct 2021 23:00:57 -0700 Subject: [PATCH 13/13] apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Manuel de la Peña --- docs/features/garbage_collector.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/garbage_collector.md b/docs/features/garbage_collector.md index 4d37c82157..b34cd8bb70 100644 --- a/docs/features/garbage_collector.md +++ b/docs/features/garbage_collector.md @@ -28,7 +28,7 @@ on test completion. [https://github.com/testcontainers/moby-ryuk](Ryuk) (also referred to as `Reaper` in this package) removes containers/networks/volumes created by Testcontainers-Go after a specified delay. It is a project developed by the -TestContainers organization and is used across the board for for many of the +TestContainers organization and is used across the board for many of the different language implementations. When you run one test, you will see an additional container called `ryuk` diff --git a/docs/index.md b/docs/index.md index c9729ab985..0650d3e7c8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,5 +23,5 @@ See [LICENSE](https://github.com/testcontainers/testcontainers-go/blob/master/LI ## Copyright -Copyright (c) 2018-2021 Gianluca Arbezzano and other authors. Check out our +Copyright (c) 2018-present Gianluca Arbezzano and other authors. Check out our [lovely contributors](https://github.com/testcontainers/testcontainers-go/graphs/contributors).