Skip to content

Commit

Permalink
Merge branch 'main' into bump-transitive-deps-security-concerns
Browse files Browse the repository at this point in the history
* main:
  Add system requirements parent docs page for podman and colima (#562)
  Support for cap-add/cap-drop (#555)
  fix container NetworkMode usage (#560)
  chore: use hashed versions of test-summary action (#556)
  chore: use container.State() function in tests (#543)
  Log docker server info (#548)
  docs: add docs regarding Colima usage (#547)
  chore: add emoji to breaking changes in release drafter (#542)
  chore: add CONTRIBUTING file (#539)
  issue #537 Rename the wait/multi.go file to wait/all.go (#541)
  docs: add a basic layout for wait strategies in docs (#536)
  docs: improve consistency and fix typos (#534)
  chore: do not skip test (#528)
  chore: include test flakiness in the release drafter (#535)
  chore: retire old versions of Go (#530)
  • Loading branch information
mdelapenya committed Oct 10, 2022
2 parents 36d81ce + d118f89 commit e71db4a
Show file tree
Hide file tree
Showing 39 changed files with 565 additions and 507 deletions.
3 changes: 2 additions & 1 deletion .github/release-drafter.yml
Expand Up @@ -6,7 +6,7 @@ template: |
categories:
- title: 🚀 Features
label: type/feature
- title: BC Break
- title: ⚠️ Breaking Changes
label: type/bc-break
- title: 🐛 Bug Fixes
label: type/bug
Expand All @@ -15,6 +15,7 @@ categories:
- title: 🧹 Housekeeping
labels:
- type/housekeeping
- type/test-flakiness
- type/test-improvement
- title: 📦 Dependency updates
label: dependencies
4 changes: 2 additions & 2 deletions .github/workflows/ci-podman.yml
Expand Up @@ -6,7 +6,7 @@ jobs:
build:
strategy:
matrix:
go-version: [1.16.x, 1.17.x, 1.x]
go-version: [1.18.x, 1.x]
runs-on: ubuntu-22.04
steps:
- name: Set up Go
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
./scripts/check_environment.sh
- name: Test Summary
uses: test-summary/action@v1
uses: test-summary/action@77bb5a9f9c572416423f9a157cbf1159c1e75a4c
with:
paths: "**/TEST-*.xml"
if: always()
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -18,7 +18,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.16.x, 1.17.x, 1.x]
go-version: [1.18.x, 1.x]
platform: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
./scripts/check_environment.sh
- name: Test Summary
uses: test-summary/action@v1
uses: test-summary/action@77bb5a9f9c572416423f9a157cbf1159c1e75a4c
with:
paths: "**/TEST-*.xml"
if: always()
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -11,3 +11,4 @@ src/pip-delete-this-directory.txt
.DS_Store

cover.txt
TEST-*.xml
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
@@ -0,0 +1,13 @@
# Contributing

Please see the [main contributing guidelines](./docs/contributing.md).

There are additional docs describing [contributing documentation changes](./docs/contributing_docs.md).

### GitHub Sponsorship

Testcontainers is [in the GitHub Sponsors program](https://github.com/sponsors/testcontainers)!

This repository is supported by our sponsors, meaning that issues are eligible to have a 'bounty' attached to them by sponsors.

Please see [the bounty policy page](https://golang.testcontainers.org/bounty) if you are interested, either as a sponsor or as a contributor.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -9,6 +9,7 @@ test-unit:
--format short-verbose \
--rerun-fails=5 \
--packages="./..." \
--junitfile TEST-unit.xml \
-- -coverprofile=cover.txt

.PHONY: test-e2e
Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -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 Go package that makes it simple to create and clean up container-based dependencies for
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.

Expand Down Expand Up @@ -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 is rendered at
More information about Testcontainers-go can be found in [./docs](./docs), which is rendered at
[golang.testcontainers.org](https://golang.testcontainers.org).
4 changes: 3 additions & 1 deletion container.go
Expand Up @@ -116,7 +116,9 @@ type ContainerRequest struct {
AlwaysPullImage bool // Always pull image
ImagePlatform string // ImagePlatform describes the platform which the image runs on.
Binds []string
ShmSize int64 // Amount of memory shared with the host (in bytes)
ShmSize int64 // Amount of memory shared with the host (in bytes)
CapAdd []string // Add Linux capabilities
CapDrop []string // Drop Linux capabilities
}

type (
Expand Down
28 changes: 27 additions & 1 deletion docker.go
Expand Up @@ -15,6 +15,7 @@ import (
"os/exec"
"path/filepath"
"strings"
"sync"
"time"

"github.com/docker/docker/api/types/filters"
Expand All @@ -40,13 +41,15 @@ var (
// Implement interfaces
_ Container = (*DockerContainer)(nil)

logOnce sync.Once
ErrDuplicateMountTarget = errors.New("duplicate mount target detected")
)

const (
Bridge = "bridge" // Bridge network name (as well as driver)
Podman = "podman"
ReaperDefault = "reaper_default" // Default network name when bridge is not available
packagePath = "github.com/testcontainers/testcontainers-go"
)

// DockerContainer represents a container started using Docker
Expand Down Expand Up @@ -770,9 +773,30 @@ func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error
config: tcConfig,
}

// log docker server info only once
logOnce.Do(p.logDockerServerInfo)

return p, nil
}

func (p *DockerProvider) logDockerServerInfo() {
infoMessage := `%v - Connected to docker:
Server Version: %v
API Version: %v
Operating System: %v
Total Memory: %v MB
`

info, err := p.client.Info(context.Background())
if err != nil {
p.Logger.Printf("failed getting information about docker server: %s", err)
}

p.Logger.Printf(infoMessage, packagePath,
info.ServerVersion, p.client.ClientVersion(),
info.OperatingSystem, info.MemTotal/1024/1024)
}

// configureTC reads from testcontainers properties file, if it exists
// it is possible that certain values get overridden when set as environment variables
func configureTC() TestContainersConfig {
Expand Down Expand Up @@ -969,7 +993,7 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque
}

exposedPorts := req.ExposedPorts
if len(exposedPorts) == 0 {
if len(exposedPorts) == 0 && !req.NetworkMode.IsContainer() {
image, _, err := p.client.ImageInspectWithRaw(ctx, tag)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1009,6 +1033,8 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque
NetworkMode: req.NetworkMode,
Resources: req.Resources,
ShmSize: req.ShmSize,
CapAdd: req.CapAdd,
CapDrop: req.CapDrop,
}

endpointConfigs := map[string]*network.EndpointSettings{}
Expand Down
108 changes: 79 additions & 29 deletions docker_test.go
Expand Up @@ -17,6 +17,7 @@ import (
"time"

"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/go-units"
"github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -457,11 +458,7 @@ func TestContainerTerminationResetsState(t *testing.T) {

func TestContainerStopWithReaper(t *testing.T) {
ctx := context.Background()
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
t.Fatal(err)
}
client.NegotiateAPIVersion(ctx)

nginxA, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Expand All @@ -476,38 +473,34 @@ func TestContainerStopWithReaper(t *testing.T) {
require.NoError(t, err)
terminateContainerOnEnd(t, ctx, nginxA)

containerID := nginxA.GetContainerID()
resp, err := client.ContainerInspect(ctx, containerID)
state, err := nginxA.State(ctx)
if err != nil {
t.Fatal(err)
}
if resp.State.Running != true {
if state.Running != true {
t.Fatal("The container shoud be in running state")
}
stopTimeout := 10 * time.Second
err = nginxA.Stop(ctx, &stopTimeout)
if err != nil {
t.Fatal(err)
}
resp, err = client.ContainerInspect(ctx, containerID)

state, err = nginxA.State(ctx)
if err != nil {
t.Fatal(err)
}
if resp.State.Running != false {
if state.Running != false {
t.Fatal("The container shoud not be running")
}
if resp.State.Status != "exited" {
if state.Status != "exited" {
t.Fatal("The container shoud be in exited state")
}
}

func TestContainerTerminationWithReaper(t *testing.T) {
ctx := context.Background()
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
t.Fatal(err)
}
client.NegotiateAPIVersion(ctx)

nginxA, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Expand All @@ -521,31 +514,27 @@ func TestContainerTerminationWithReaper(t *testing.T) {
if err != nil {
t.Fatal(err)
}
containerID := nginxA.GetContainerID()
resp, err := client.ContainerInspect(ctx, containerID)

state, err := nginxA.State(ctx)
if err != nil {
t.Fatal(err)
}
if resp.State.Running != true {
if state.Running != true {
t.Fatal("The container shoud be in running state")
}
err = nginxA.Terminate(ctx)
if err != nil {
t.Fatal(err)
}
_, err = client.ContainerInspect(ctx, containerID)
_, err = nginxA.State(ctx)
if err == nil {
t.Fatal("expected error from container inspect.")
}
}

func TestContainerTerminationWithoutReaper(t *testing.T) {
ctx := context.Background()
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
t.Fatal(err)
}
client.NegotiateAPIVersion(ctx)

nginxA, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Expand All @@ -560,19 +549,20 @@ func TestContainerTerminationWithoutReaper(t *testing.T) {
if err != nil {
t.Fatal(err)
}
containerID := nginxA.GetContainerID()
resp, err := client.ContainerInspect(ctx, containerID)

state, err := nginxA.State(ctx)
if err != nil {
t.Fatal(err)
}
if resp.State.Running != true {
if state.Running != true {
t.Fatal("The container shoud be in running state")
}
err = nginxA.Terminate(ctx)
if err != nil {
t.Fatal(err)
}
_, err = client.ContainerInspect(ctx, containerID)

_, err = nginxA.State(ctx)
if err == nil {
t.Fatal("expected error from container inspect.")
}
Expand Down Expand Up @@ -2225,6 +2215,39 @@ func TestContainerWithReaperNetwork(t *testing.T) {
assert.NotNil(t, cnt.NetworkSettings.Networks[networks[1]])
}

func TestContainerCapAdd(t *testing.T) {
if providerType == ProviderPodman {
t.Skip("Rootless Podman does not support setting cap-add/cap-drop")
}

ctx := context.Background()

expected := "IPC_LOCK"

nginx, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Image: nginxAlpineImage,
ExposedPorts: []string{nginxDefaultPort},
WaitingFor: wait.ForListeningPort(nginxDefaultPort),
CapAdd: []string{expected},
},
Started: true,
})
require.NoError(t, err)
terminateContainerOnEnd(t, ctx, nginx)

dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err)
defer dockerClient.Close()

containerID := nginx.GetContainerID()
resp, err := dockerClient.ContainerInspect(ctx, containerID)
require.NoError(t, err)

assert.Equal(t, strslice.StrSlice{expected}, resp.HostConfig.CapAdd)
}

func TestContainerRunningCheckingStatusCode(t *testing.T) {
ctx := context.Background()
req := ContainerRequest{
Expand Down Expand Up @@ -2334,6 +2357,33 @@ func TestProviderHasConfig(t *testing.T) {
assert.NotNil(t, provider.Config(), "expecting DockerProvider to provide the configuration")
}

func TestNetworkModeWithContainerReference(t *testing.T) {
ctx := context.Background()
nginxA, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Image: nginxAlpineImage,
},
Started: true,
})

require.NoError(t, err)
terminateContainerOnEnd(t, ctx, nginxA)

networkMode := fmt.Sprintf("container:%v", nginxA.GetContainerID())
nginxB, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Image: nginxAlpineImage,
NetworkMode: container.NetworkMode(networkMode),
},
Started: true,
})

require.NoError(t, err)
terminateContainerOnEnd(t, ctx, nginxB)
}

// creates a temporary dir in which the files will be extracted. Then it will compare the bytes of each file in the source with the bytes from the copied-from-container file
func assertExtractedFiles(t *testing.T, ctx context.Context, container Container, hostFilePath string, containerFilePath string) {
// create all copied files into a temporary dir
Expand Down

0 comments on commit e71db4a

Please sign in to comment.