8e6e53cf63
When running the test suite in CI (where requests are centralized from relatively few IPs), we'd occasionally hit Dockerhub's rate limits. Luckily Hashicorp runs a (limited) public mirror of the containers we need, so we can switch to them here in the tests. For consistency between developer and CI, we've opted to have the tests always pull from the Hashicorp mirror, rather than updating the CI runner to prefer the mirror. We exclude nomad and influxdb as we don't presently mirror these repos. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
163 lines
4 KiB
Go
163 lines
4 KiB
Go
package couchdb
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
"github.com/hashicorp/vault/helper/testhelpers/docker"
|
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
|
"github.com/hashicorp/vault/sdk/physical"
|
|
)
|
|
|
|
func TestCouchDBBackend(t *testing.T) {
|
|
cleanup, config := prepareCouchdbDBTestContainer(t)
|
|
defer cleanup()
|
|
|
|
logger := logging.NewVaultLogger(log.Debug)
|
|
|
|
b, err := NewCouchDBBackend(map[string]string{
|
|
"endpoint": config.URL().String(),
|
|
"username": config.username,
|
|
"password": config.password,
|
|
}, logger)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
physical.ExerciseBackend(t, b)
|
|
physical.ExerciseBackend_ListPrefix(t, b)
|
|
}
|
|
|
|
func TestTransactionalCouchDBBackend(t *testing.T) {
|
|
cleanup, config := prepareCouchdbDBTestContainer(t)
|
|
defer cleanup()
|
|
|
|
logger := logging.NewVaultLogger(log.Debug)
|
|
|
|
b, err := NewTransactionalCouchDBBackend(map[string]string{
|
|
"endpoint": config.URL().String(),
|
|
"username": config.username,
|
|
"password": config.password,
|
|
}, logger)
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
physical.ExerciseBackend(t, b)
|
|
physical.ExerciseBackend_ListPrefix(t, b)
|
|
}
|
|
|
|
type couchDB struct {
|
|
baseURL url.URL
|
|
dbname string
|
|
username string
|
|
password string
|
|
}
|
|
|
|
func (c couchDB) Address() string {
|
|
return c.baseURL.Host
|
|
}
|
|
|
|
func (c couchDB) URL() *url.URL {
|
|
u := c.baseURL
|
|
u.Path = c.dbname
|
|
return &u
|
|
}
|
|
|
|
var _ docker.ServiceConfig = &couchDB{}
|
|
|
|
func prepareCouchdbDBTestContainer(t *testing.T) (func(), *couchDB) {
|
|
// If environment variable is set, assume caller wants to target a real
|
|
// DynamoDB.
|
|
if os.Getenv("COUCHDB_ENDPOINT") != "" {
|
|
return func() {}, &couchDB{
|
|
baseURL: url.URL{Host: os.Getenv("COUCHDB_ENDPOINT")},
|
|
username: os.Getenv("COUCHDB_USERNAME"),
|
|
password: os.Getenv("COUCHDB_PASSWORD"),
|
|
}
|
|
}
|
|
|
|
runner, err := docker.NewServiceRunner(docker.RunOptions{
|
|
ContainerName: "couchdb",
|
|
ImageRepo: "docker.mirror.hashicorp.services/library/couchdb",
|
|
ImageTag: "1.6",
|
|
Ports: []string{"5984/tcp"},
|
|
DoNotAutoRemove: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Could not start local CouchDB: %s", err)
|
|
}
|
|
|
|
svc, err := runner.StartService(context.Background(), setupCouchDB)
|
|
if err != nil {
|
|
t.Fatalf("Could not start local CouchDB: %s", err)
|
|
}
|
|
|
|
return svc.Cleanup, svc.Config.(*couchDB)
|
|
}
|
|
|
|
func setupCouchDB(ctx context.Context, host string, port int) (docker.ServiceConfig, error) {
|
|
c := &couchDB{
|
|
baseURL: url.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", host, port)},
|
|
dbname: fmt.Sprintf("vault-test-%d", time.Now().Unix()),
|
|
username: "admin",
|
|
password: "admin",
|
|
}
|
|
|
|
{
|
|
resp, err := http.Get(c.baseURL.String())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("expected couchdb to return status code 200, got (%s) instead", resp.Status)
|
|
}
|
|
}
|
|
|
|
{
|
|
req, err := http.NewRequest("PUT", c.URL().String(), nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not create create database request: %q", err)
|
|
}
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not create database: %q", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusCreated {
|
|
bs, _ := ioutil.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("failed to create database: %s %s\n", resp.Status, string(bs))
|
|
}
|
|
}
|
|
|
|
{
|
|
u := c.baseURL
|
|
u.Path = fmt.Sprintf("_config/admins/%s", c.username)
|
|
req, err := http.NewRequest("PUT", u.String(), strings.NewReader(fmt.Sprintf(`"%s"`, c.password)))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Could not create admin user request: %q", err)
|
|
}
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Could not create admin user: %q", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
bs, _ := ioutil.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("Failed to create admin user: %s %s\n", resp.Status, string(bs))
|
|
}
|
|
}
|
|
|
|
return c, nil
|
|
}
|