open-vault/physical/couchdb/couchdb_test.go
2023-04-24 14:25:50 -04:00

166 lines
4 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
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/sdk/helper/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
}