{"id":24280811,"url":"https://github.com/daichitakahashi/confort","last_synced_at":"2026-04-16T16:03:47.771Z","repository":{"id":40773918,"uuid":"490384900","full_name":"daichitakahashi/confort","owner":"daichitakahashi","description":"Unit test with Docker containers in Go","archived":false,"fork":false,"pushed_at":"2023-10-27T11:14:45.000Z","size":629,"stargazers_count":1,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-16T02:36:23.394Z","etag":null,"topics":["containers","docker","go","golang","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daichitakahashi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-09T17:39:46.000Z","updated_at":"2022-10-11T09:31:38.000Z","dependencies_parsed_at":"2024-06-21T01:45:14.516Z","dependency_job_id":"f72e5677-f866-4b0d-a395-387d63c658ea","html_url":"https://github.com/daichitakahashi/confort","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daichitakahashi%2Fconfort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daichitakahashi%2Fconfort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daichitakahashi%2Fconfort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daichitakahashi%2Fconfort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daichitakahashi","download_url":"https://codeload.github.com/daichitakahashi/confort/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242039719,"owners_count":20061927,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["containers","docker","go","golang","testing"],"created_at":"2025-01-16T02:35:10.145Z","updated_at":"2026-04-16T16:03:47.742Z","avatar_url":"https://github.com/daichitakahashi.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unit test with Docker containers in Go\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/daichitakahashi/confort.svg)](https://pkg.go.dev/github.com/daichitakahashi/confort)\n[![coverage](https://img.shields.io/endpoint?style=flat-square\u0026url=https%3A%2F%2Fdaichitakahashi.github.io%2Fconfort%2Fcoverage.json)](https://daichitakahashi.github.io/confort/coverage.html)\n\nThis project aims to use Docker containers in parallelized tests efficiently.  \nPackage `confort` provides test utilities to start Docker containers and generate unique identifiers.\n\n## Features\n### 1. Use Docker containers with `go test`\nIf you want to run a unit test which depends on Docker container, all you need\nto do is declare the container in the test code with `confort.Confort` and run \n`go test`.  \nThe desired container will be started in the test. Also, the test code can reuse \nexisting containers.\n\n### 2. Share containers on parallelized tests\nIn some cases, starting a Docker container requires a certain amount of computing \nresources and time.  \nSometimes there are several unit tests that requires the same Docker container.\n`confort.Confort` and `confort` command enables us to share it and make testing \nmore efficient. And we can choose shared locking not only exclusive.\n\n### 3. Avoid conflict between tests by using unique identifier generator\nTo efficiently use containers simultaneously from parallelized tests, it is \neffective to make the resource name created on the container unique for each test \n(e.g., database name or realm name).\n`unique.Unique` helps generating unique names.\n\n## Unit Test Example\n### Single package test\n```go\nfunc TestExample(t *testing.T) {\n    ctx := context.Background()\n    \n    // CFT_NAMESPACE=your_ci_id\n    cft, err := confort.New(ctx,\n        confort.WithNamespace(\"fallback-namespace\", false),\n    )\n    if err != nil {\n        t.Fatal(err)\n    }\n    t.Cleanup(func() {\n        _ = cft.Close()\n    })\n\n    // start container\n    db, err := cft.Run(t, ctx, \u0026confort.ContainerParams{\n        Name:  \"db\",\n        Image: \"postgres:14.4-alpine3.16\",\n        Env: map[string]string{\n            \"POSTGRES_USER\":     dbUser,\n            \"POSTGRES_PASSWORD\": dbPassword,\n        },\n        ExposedPorts: []string{\"5432/tcp\"},\n        Waiter:       wait.Healthy(),\n    },\n        // pull image if not exists\n        confort.WithPullOptions(\u0026types.ImagePullOptions{}, os.Stderr),\n        // enable health check\n        confort.WithContainerConfig(func(config *container.Config) {\n            config.Healthcheck = \u0026container.HealthConfig{\n                Test:     []string{\"CMD-SHELL\", \"pg_isready\"},\n                Interval: 5 * time.Second,\n                Timeout:  3 * time.Second,\n            }\n        }),\n    )\n    if err != nil {\n        t.Fatal(err)\n    }\n    \n    // use container exclusively. the container will be released after the test finished\n    // UseShared is also available\n    ports, release, err := db.UseExclusive(ctx)\n    if err != nil {\n        t.Fatal(err)\n    }\n    t.Cleanup(release)\n    addr := ports.HostPort(\"5432/tcp\")\n    // connect PostgreSQL using `addr`\n\t\n    uniq := unique.Must(unique.String(ctx, 12))\n    schema := uniq.Must(t)\n    // create a schema using `schema` as its name\n}\n```\n\n### Parallelized test with `confort` command\n```go\nfunc TestExample(t *testing.T) {\n    ctx := context.Background()\n\n    // Connect beacon server using an address from `.confort.lock` or CFT_BEACON_ADDR.\n    // The function does not fail even if the beacon server is not enabled. But beacon.Enabled == false.\n\n    // CFT_NAMESPACE=your_ci_id\n    cft, err := confort.New(ctx,\n        confort.WithNamespace(\"fallback-namespace\", false),\n        // Following line enables an integration with `confort` command if it's available.\n        // Connect will be established using an address of the beacon server from `.confort.lock` or CFT_BEACON_ADDR.\n        // Exclusion control is performed through the beacon server.\n        confort.WithBeacon(beacon),\n    )\n\n    // ...\n\n    uniq := unique.Must(unique.String(ctx, 12,\n        // Following line enables an integration with `confort` command too. \n        // This stores the values created across the entire test\n        // and helps create unique one.\n        unique.WithBeacon(t, ctx, \"database-name\"), \n    ))\n    // ...\n}\n```\n\n## Run test\n### Unit test of a package\n```shell\n$ go test .\n```\n\n### Unit tests of all packages recursively\n```shell\n$ confort test -- ./...\n```\n`confort test` command launches *beacon server* that helps exclusion control of \ncontainers in parallelized tests and run test. Command line arguments after \"--\" \nare passed to `go test`. The `go` command is appropriately selected according to \n\"go.mod\" using [gocmd](https://github.com/daichitakahashi/gocmd).  \nAfter tests finished, all created resources will be removed (removal policy is\nconfigurable with option \"-policy\").\n\n### In your CI script\nShort example of *.gitlab-ci.yml*:\n```yaml\nvariables:\n  CONFORT: github.com/daichitakahashi/confort/cmd/confort\n  CFT_NAMESPACE: $CI_JOB_ID # use job id to avoid conflict with other tests\ntest:\n  script:\n    - go run $CONFORT start \u0026 # launch beacon server\n    - go test ./... # run test using beacon server\n  after_script:\n    - go run $CONFORT stop # cleanup created Docker resources and stop beacon server safely\n```\n\nOff course, you can also use `confort test` command.\n\n## Detail of `confort` command\nThe functionality of this package consists of Go package `confort` and command `confort`.\nThese are communicating with each other in gRPC protocol, and each version should be matched.\n\nTo avoid version mismatches, \"go run\" is recommended instead of \"go install\".\n\n### confort test\nStart the beacon server and execute tests.  \nAfter the tests are finished, the beacon server will be stopped automatically.  \nIf you want to use options of \"go test\", put them after \"--\".\n\nThere are following options.\n\n#### `-go=\u003cgo version\u003e`\nSpecify go version that runs tests.\n\"-go=mod\" enables to use go version written in your `go.mod`.\n\n#### `-go-mode=\u003cmode\u003e`\nSpecify detection mode of -go option. Default value is \"fallback\".\n* \"exact\" finds go command that has the exact same version as given in \"-go\"\n* \"latest\" finds the latest go command that has the same major version as given in \"-go\"\n* \"fallback\" behaves like \"latest\", but if no command was found, fallbacks to \"go\" command\n\n#### `-namespace=\u003cnamespace\u003e`\nSpecify the namespace(prefix) of docker resources created by `confort.Confort`.\nThe value is set as `CFT_NAMESPACE`.\n\n#### `-policy=\u003cpolicy\u003e`\nSpecify resource handling policy. The value is set as `CFT_RESOURCE_POLICY`. Default value is \"reuse\".\n* With \"error\", the existing same resource(network and container) makes test failed\n* With \"reuse\", tests reuse resources if already exist\n* \"reusable\" is similar to \"reuse\", but created resources will not be removed after the tests finished\n* \"takeover\" is also similar to \"reuse\", but reused resources will be removed after the tests\n\n### confort start\nStart the beacon server and output its endpoint to the lock file(\".confort.lock\"). If the lock file already exists, this command fails.  \nSee the document of `confort.WithBeacon`.\n\nThere is a following option.\n\n#### `-lock-file=\u003cfilename\u003e`\nSpecify the user-defined filename of the lock file. Default value is \".confort.lock\".  \nWith this option, to tell the endpoint to the test code, you have to set file name as environment variable `CFT_LOCKFILE`.\nIf `CFT_LOCKFILE` is already set, the command uses the value as default.\n\n### confort stop\nStop the beacon server started by `confort start` command.  \nThe target server address will be read from lock file(\".confort.lock\"), and the lock file will be removed.\nIf \"confort start\" has accompanied by \"-lock-file\" option, this command requires the same.\n\nThere is a following option.\n\n#### `-lock-file=\u003cfilename\u003e`\nSpecify the user-defined filename of the lock file. It is the same as the `-lock-file` option of `confort start`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaichitakahashi%2Fconfort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaichitakahashi%2Fconfort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaichitakahashi%2Fconfort/lists"}