Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

\#1500 - prototype for using testcontainers-go for dependencies #1544

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,10 @@ 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
ATHENS_USE_TEST_CONTAINERS: 1
GCS_SERVICE_ACCOUNT:
from_secret: GCS_SERVICE_ACCOUNT
GCS_PROJECT_ID:
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 ./...
12 changes: 7 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
image: Visual Studio 2019
build: off

clone_folder: c:\gopath\src\github.com\gomods\athens

image: Previous Visual Studio 2019

environment:
GOPATH: c:\gopath
GO111MODULE: on
GOPROXY: https://proxy.golang.org
SKIP_UNTIL_113: true
ATHENS_USE_TEST_CONTAINERS: 1

stack: go 1.13

stack: go 1.14
install:
- choco upgrade docker-desktop

test_script:
- go version
- go test ./...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ClaytonNorthey92 we still need to run at least unit tests on windows. One idea would be to add an env var to turn off the testcontainers tests and set it in appveyor but not in GH actions. What do you think?

Copy link
Author

@ClaytonNorthey92 ClaytonNorthey92 Mar 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the issue here came from trying to start the reaper containers on windows (the containers that run and ensure that the containers we start get killed at the end of the tests), but you can optionally skip the reaper containers.

I think that since, according to appveyor's documentation, they don't preserve any VMs between builds, we can safely skip the reaper in appveyor tests. So I think we should add that env variable like TESTCONTAINERS_SKIP_REAPER, if that is set to 1 then we skip the reaper builds and we should be okay (I think)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am testing this theory out now...I accidentally got a build stuck debugging...so I am going to wait for that to timeout and fail to keep on testing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @arschles how do you feel about putting integration tests into their own package? the using a build tag to ignore them by default, then you can pass in the tag to enable them? that should be able to be done just from the code and the config files and wouldn't require a change to the environment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with me RE the different package. I'd rather have them enabled by default and pass a tag to disable them. Are you cool with that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that makes sense to me, just need a way to cleanly include/not include them

I can work on this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great! We had an idea in #1500 to not turn off the tests completely, but just to turn off the testcontainers logic based on a tag. I laid it out here

What do you think about that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just left a comment

- go test -v ./...
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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arschles do you have a Windows machine? Could you ensure that the testunit service works on Windows via the make command to run unit tests? If it fails, could you paste the error here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is make test-unit-docker

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try, but let's try to get testcontainers-less appveyor tests back 😄

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
9 changes: 3 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ require (
github.com/bsm/redislock v0.4.2
github.com/codegangsta/negroni v1.0.0 // indirect
github.com/fatih/color v1.7.0
github.com/go-playground/locales v0.12.1 // indirect
github.com/go-playground/universal-translator v0.16.0 // indirect
github.com/go-redis/redis/v7 v7.2.0
github.com/go-sql-driver/mysql v1.5.0
github.com/gobuffalo/envy v1.6.7
github.com/gobuffalo/httptest v1.0.4
github.com/golang/protobuf v1.3.3 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-cmp v0.5.1
github.com/google/uuid v1.1.1
github.com/google/uuid v1.1.2
github.com/gorilla/mux v1.6.2
github.com/hashicorp/go-multierror v1.0.0
github.com/hashicorp/hcl2 v0.0.0-20190503213020-640445e16309
Expand All @@ -37,9 +34,9 @@ require (
github.com/philhofer/fwd v1.0.0 // 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.5.1
github.com/stretchr/testify v1.6.1
github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245
github.com/testcontainers/testcontainers-go v0.9.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
58 changes: 58 additions & 0 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