Skip to content

Commit

Permalink
\gomods#1500 - prototype for using testcontainers-go for dependencies
Browse files Browse the repository at this point in the history
Prototype for using testcontainers for dependencies: mongodb, minio, and
redis
  • Loading branch information
ClaytonNorthey92 committed May 16, 2020
1 parent 90af973 commit 2c17304
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 164 deletions.
7 changes: 2 additions & 5 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,8 @@ steps:
GO111MODULE: on
ATHENS_MONGO_STORAGE_URL: mongodb://mongo:27017
ATHENS_MINIO_ENDPOINT: minio:9000
REDIS_TEST_ENDPOINT: redis:6379
REDIS_SENTINEL_TEST_ENDPOINT: redis-sentinel:26379
REDIS_SENTINEL_TEST_MASTER_NAME: redis-1
REDIS_SENTINEL_TEST_PASSWORD: sekret
PROTECTED_REDIS_TEST_ENDPOINT: protectedredis:6380
ATHENS_REDIS_ENDPOINT: redis:6379
ATHENS_PROTECTED_REDIS_ENDPOINT: protectedredis:6380
ATHENS_PROTECTED_REDIS_PASSWORD: AthensPass1
GCS_SERVICE_ACCOUNT:
from_secret: GCS_SERVICE_ACCOUNT
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Go
on:
- push
- pull_request
jobs:

build:
name: Build
runs-on: ubuntu-latest
steps:

- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v1

- name: Test
run: ATHENS_USE_TEST_CONTAINERS=1 go test -v ./...
7 changes: 4 additions & 3 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
image: Visual Studio 2017
build: off

clone_folder: c:\gopath\src\github.com\gomods\athens
Expand All @@ -8,8 +9,8 @@ environment:
GOPROXY: https://proxy.golang.org
SKIP_UNTIL_113: true

stack: go 1.14
stack: go 1.13

test_script:
- go test ./...

# remove this comment
- go test -v -tags=unit ./...
7 changes: 2 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@ services:
args:
GOLANG_VERSION: 1.14
command: ["./scripts/test_unit.sh"]
volumes:
- /var/run/docker.sock:/var/run/docker.sock # test this on windows, it might be different
environment:
- GO_ENV=test
- ATHENS_MINIO_ENDPOINT=minio:9000
- ATHENS_MONGO_STORAGE_URL=mongodb://mongo:27017
- TIMEOUT=20 # in case the mongo dependency takes longer to start up
- ATHENS_STORAGE_TYPE=mongo
depends_on:
- mongo
- minio
teste2e:
build:
context: .
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ require (
github.com/minio/minio-go/v6 v6.0.43
github.com/mitchellh/go-homedir v1.1.0
github.com/philhofer/fwd v1.0.0 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.1.2
github.com/spf13/pflag v1.0.3 // indirect
github.com/stretchr/testify v1.4.0
github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245
github.com/testcontainers/testcontainers-go v0.2.0
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 // indirect
github.com/tinylib/msgp v1.0.2 // indirect
github.com/unrolled/secure v0.0.0-20181221173256-0d6b5bb13069
Expand Down
124 changes: 36 additions & 88 deletions go.sum

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pkg/stash/with_redis.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build !unit

package stash

import (
Expand Down
89 changes: 80 additions & 9 deletions pkg/stash/with_redis_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build !unit

package stash

import (
Expand All @@ -11,24 +13,93 @@ import (

"github.com/gomods/athens/pkg/storage"
"github.com/gomods/athens/pkg/storage/mem"
testcontainers "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
"golang.org/x/sync/errgroup"
)

var useTestContainers = os.Getenv("ATHENS_USE_TEST_CONTAINERS")
var redisEndpoint string
var redisProtectedEndpoint string
var redisPassword string

func TestMain(m *testing.M) {
redisPassword = os.Getenv("ATHENS_REDIS_PROTECTED_PASSWORD")
if redisPassword == "" {
redisPassword = "mydefaultredispassword"
}

if useTestContainers != "1" {
redisEndpoint = os.Getenv("ATHENS_REDIS_ENDPOINT")
redisProtectedEndpoint = os.Getenv("ATHENS_REDIS_PROTECTED_ENDPOINT")
redisPassword = os.Getenv("ATHENS_PROTECTED_REDIS_PASSWORD")
os.Exit(m.Run())
}

ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "redis:alpine",
ExposedPorts: []string{"6379/tcp"},
Env: map[string]string{
"REDIS_PASSWORD": redisPassword,
},
Cmd: []string{"sh", "-c", "redis-server --requirepass \"$REDIS_PASSWORD\""},
WaitingFor: wait.ForLog("Ready to accept connections").WithStartupTimeout(time.Minute * 1),
}

c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})

if err != nil {
os.Exit(1)
}

ep, err := c.Endpoint(context.Background(), "")
if err != nil {
panic(err.Error())
}

redisProtectedEndpoint = ep
defer c.Terminate(ctx)

req = testcontainers.ContainerRequest{
Image: "redis:alpine",
ExposedPorts: []string{"6379/tcp"},
WaitingFor: wait.ForLog("Ready to accept connections").WithStartupTimeout(time.Minute * 1),
}

c, err = testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})

if err != nil {
os.Exit(1)
}

ep, err = c.Endpoint(context.Background(), "")
if err != nil {
panic(err.Error())
}

redisEndpoint = ep
defer c.Terminate(ctx)

os.Exit(m.Run())
}

// WithRedisLock will ensure that 5 concurrent requests will all get the first request's
// response. We can ensure that because only the first response does not return an error
// and therefore all 5 responses should have no error.
func TestWithRedisLock(t *testing.T) {
endpoint := os.Getenv("REDIS_TEST_ENDPOINT")
password := os.Getenv("ATHENS_REDIS_PASSWORD")
if len(endpoint) == 0 {
t.SkipNow()
}
strg, err := mem.NewStorage()
if err != nil {
t.Fatal(err)
}
ms := &mockRedisStasher{strg: strg}
wrapper, err := WithRedisLock(endpoint, password, storage.WithChecker(strg))
wrapper, err := WithRedisLock(redisEndpoint, "", storage.WithChecker(strg))
if err != nil {
t.Fatal(err)
}
Expand All @@ -53,8 +124,8 @@ func TestWithRedisLock(t *testing.T) {
// Verify with WithRedisLock working with password protected redis
// Same logic as the TestWithRedisLock test.
func TestWithRedisLockWithPassword(t *testing.T) {
endpoint := os.Getenv("PROTECTED_REDIS_TEST_ENDPOINT")
password := os.Getenv("ATHENS_PROTECTED_REDIS_PASSWORD")
endpoint := redisProtectedEndpoint
password := redisPassword
if len(endpoint) == 0 {
t.SkipNow()
}
Expand Down Expand Up @@ -88,7 +159,7 @@ func TestWithRedisLockWithPassword(t *testing.T) {
// Verify the WithRedisLock fails with the correct error when trying
// to connect with the wrong password.
func TestWithRedisLockWithWrongPassword(t *testing.T) {
endpoint := os.Getenv("PROTECTED_REDIS_TEST_ENDPOINT")
endpoint := redisProtectedEndpoint
password := ""
if len(endpoint) == 0 {
t.SkipNow()
Expand Down
66 changes: 50 additions & 16 deletions pkg/storage/minio/minio_test.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,67 @@
// +build !unit

package minio

import (
"context"
"os"
"testing"
"time"

"github.com/gomods/athens/pkg/config"
"github.com/gomods/athens/pkg/storage/compliance"
testcontainers "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

var useTestContainers = os.Getenv("ATHENS_USE_TEST_CONTAINERS")
var minioEndpoint string

func TestMain(m *testing.M) {
if useTestContainers != "1" {
os.Exit(m.Run())
minioEndpoint = os.Getenv("ATHENS_MINIO_ENDPOINT")
}

ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "minio/minio:latest",
ExposedPorts: []string{"9000/tcp"},
WaitingFor: wait.ForLog("Endpoint:").WithStartupTimeout(time.Minute * 1),
Cmd: []string{"server", "/data"},
Env: map[string]string{
"MINIO_ACCESS_KEY": "minio",
"MINIO_SECRET_KEY": "minio123",
},
}

c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})

if err != nil {
panic(err.Error())
}

ep, err := c.Endpoint(context.Background(), "")
if err != nil {
panic(err.Error())
}

minioEndpoint = ep
defer c.Terminate(ctx)
os.Exit(m.Run())

}

func TestBackend(t *testing.T) {
backend := getStorage(t)
compliance.RunTests(t, backend, backend.clear)
}

// TestNewStorageExists tests the logic around MakeBucket and BucketExists
func TestNewStorageExists(t *testing.T) {
url := os.Getenv("ATHENS_MINIO_ENDPOINT")
if url == "" {
t.SkipNow()
}

tests := []struct {
name string
Expand All @@ -30,7 +73,7 @@ func TestNewStorageExists(t *testing.T) {

for _, test := range tests {
backend, err := NewStorage(&config.MinioConfig{
Endpoint: url,
Endpoint: minioEndpoint,
Key: "minio",
Secret: "minio123",
Bucket: test.name,
Expand All @@ -51,18 +94,14 @@ func TestNewStorageExists(t *testing.T) {
// To ensure both paths are tested, there is a strict path error using the
// "_" and a non strict error using less than 3 characters
func TestNewStorageError(t *testing.T) {
url := os.Getenv("ATHENS_MINIO_ENDPOINT")
if url == "" {
t.SkipNow()
}

// "_" is not allowed in a bucket name
// bucket name must be bigger than 3
tests := []string{"test_bucket", "1"}

for _, bucketName := range tests {
_, err := NewStorage(&config.MinioConfig{
Endpoint: url,
Endpoint: minioEndpoint,
Key: "minio",
Secret: "minio123",
Bucket: bucketName,
Expand Down Expand Up @@ -92,13 +131,8 @@ func (s *storageImpl) clear() error {
}

func getStorage(t testing.TB) *storageImpl {
url := os.Getenv("ATHENS_MINIO_ENDPOINT")
if url == "" {
t.SkipNow()
}

backend, err := NewStorage(&config.MinioConfig{
Endpoint: url,
Endpoint: minioEndpoint,
Key: "minio",
Secret: "minio123",
Bucket: "gomods",
Expand Down
Loading

0 comments on commit 2c17304

Please sign in to comment.