Skip to content

Commit

Permalink
test: top-level helpers API for service provisioning
Browse files Browse the repository at this point in the history
  • Loading branch information
hbomb79 committed Mar 6, 2024
1 parent f57d764 commit e49dcb3
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 72 deletions.
117 changes: 64 additions & 53 deletions tests/helpers/service_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,6 @@ import (
"testing"
)

// TheaServiceRequest encapsulates information required to
// spawn a Thea service inside of a docker container.
type TheaServiceRequest struct {
// databaseName defines the name of the PostgreSQL database
// which this Thea container is expected to connect to. Provisioning
// of this database will be handled automatically if needed.
databaseName string

// ingestDirectory defines an optional directory on the
// host file system which will be mapped in to the /ingests
// path inside of the container.
ingestDirectory string

// environmentVariables can optionally be provided to
// the request to augment the mandatory API_HOST_ADDR and DB_NAME
// values that are provided. Note that overriding these values
// inside of the environmentVariables will have no effect.
environmentVariables map[string]string
}

func NewTheaContainerRequest() TheaServiceRequest {
return TheaServiceRequest{
databaseName: MasterDBName,
ingestDirectory: "",
environmentVariables: make(map[string]string, 0),
}
}

func (req TheaServiceRequest) Key() string {
return fmt.Sprintf("thea-%s-%s", req.databaseName, req.ingestDirectory)
}

func (req TheaServiceRequest) String() string {
return fmt.Sprintf("Request{db=%s ingestDir=%s}", req.databaseName, req.ingestDirectory)
}

func (req TheaServiceRequest) WithDatabaseName(databaseName string) TheaServiceRequest {
req.databaseName = databaseName
return req
}

func (req TheaServiceRequest) WithIngestDirectory(ingestPath string) TheaServiceRequest {
req.ingestDirectory = ingestPath
return req
}

func (req TheaServiceRequest) WithEnvironmentVariable(key, value string) TheaServiceRequest {
req.environmentVariables[key] = value
return req
}

type TestServicePool struct {
*sync.Mutex
databaseManager *databaseManager
Expand All @@ -73,15 +22,26 @@ func newTestServicePool() *TestServicePool {
}
}

var ServicePool *TestServicePool = newTestServicePool()
var (
servicePool *TestServicePool = newTestServicePool()
defaultServiceRequest = NewTheaContainerRequest().WithDatabaseName("integration_test")
)

func RequireDefaultThea(t *testing.T) *TestService {
return servicePool.requireThea(t, defaultServiceRequest)
}

func RequireThea(t *testing.T, request TheaServiceRequest) *TestService {
return servicePool.requireThea(t, request)
}

// RequireThea will return a TestService back to the caller based on the request provided.
// If the request matches a previously seen request (note that the environment variables inside
// the request are NOT considered when checking for matching requests) then an existing TestService
// may be returned to the caller. If no existing service can satisfy the request, then a new instance
// of Thea will be started inside of a Docker container, pointing to a new database (if specified), and
// running on a unique port number. Cleanup of services is automatic via the testing.T Cleanup functionality.
func (pool *TestServicePool) RequireThea(t *testing.T, request TheaServiceRequest) *TestService {
func (pool *TestServicePool) requireThea(t *testing.T, request TheaServiceRequest) *TestService {
pool.Lock()
defer pool.Unlock()

Expand Down Expand Up @@ -135,3 +95,54 @@ func (pool *TestServicePool) getOrCreate(t *testing.T, request TheaServiceReques
pool.databaseManager.provisionDB(t, request.databaseName)
return spawnThea(t, request)
}

// TheaServiceRequest encapsulates information required to
// request a Thea service from the service pool.
type TheaServiceRequest struct {
// databaseName defines the name of the PostgreSQL database
// which this Thea container is expected to connect to. Provisioning
// of this database will be handled automatically if needed.
databaseName string

// ingestDirectory defines an optional directory on the
// host file system which will be mapped in to the /ingests
// path inside of the container.
ingestDirectory string

// environmentVariables can optionally be provided to
// the request to augment the mandatory API_HOST_ADDR and DB_NAME
// values that are provided. Note that overriding these values
// inside of the environmentVariables will have no effect.
environmentVariables map[string]string
}

func NewTheaContainerRequest() TheaServiceRequest {
return TheaServiceRequest{
databaseName: MasterDBName,
ingestDirectory: "",
environmentVariables: make(map[string]string, 0),
}
}

func (req TheaServiceRequest) Key() string {
return fmt.Sprintf("thea-%s-%s", req.databaseName, req.ingestDirectory)
}

func (req TheaServiceRequest) String() string {
return fmt.Sprintf("Request{db=%s ingestDir=%s}", req.databaseName, req.ingestDirectory)
}

func (req TheaServiceRequest) WithDatabaseName(databaseName string) TheaServiceRequest {
req.databaseName = databaseName
return req
}

func (req TheaServiceRequest) WithIngestDirectory(ingestPath string) TheaServiceRequest {
req.ingestDirectory = ingestPath
return req
}

func (req TheaServiceRequest) WithEnvironmentVariable(key, value string) TheaServiceRequest {
req.environmentVariables[key] = value
return req
}
24 changes: 5 additions & 19 deletions tests/integration/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,15 @@ import (
"github.com/stretchr/testify/assert"
)

var (
ctx = context.Background()
defaultContainerRequest = helpers.NewTheaContainerRequest().WithDatabaseName("integration_test")
)

// requireSharedThea requests a Thea service from the service
// pool using the same DB name each time, meaning that the
// pool will provide the same service instance back to the
// test, only cleaning it up once all are compelted
// NOTE: It is important that any t.Parallel calls come
// AFTER a requireSharedThea call, as otherwise
// the pool may mistakenly consider a service finished with.
func requireSharedThea(t *testing.T) *helpers.TestService {
return helpers.ServicePool.RequireThea(t, defaultContainerRequest)
}
var ctx = context.Background()

// This package performs HTTP REST API testing against
// this controller. It requires that an instance of
// Thea is running - externally to this test suite - on the
// URL provided.

func TestLogin_InvalidCredentials(t *testing.T) {
srv := requireSharedThea(t)
srv := helpers.RequireDefaultThea(t)
t.Parallel()

resp, err := srv.NewClient(t).LoginWithResponse(ctx,
Expand All @@ -50,7 +36,7 @@ func TestLogin_InvalidCredentials(t *testing.T) {
// Ensure that a successful login returns valid tokens
// which can be used in a subsequent request to fetch the user.
func TestLogin_ValidCredentials(t *testing.T) {
srv := requireSharedThea(t)
srv := helpers.RequireDefaultThea(t)
t.Parallel()

testUser, authedClient := srv.NewClientWithRandomUser(t)
Expand Down Expand Up @@ -82,7 +68,7 @@ func TestLogin_ValidCredentials(t *testing.T) {
// of the response clearing the cookies, they should not work for
// secured endpoints.
func TestLogout_BlacklistsTokens(t *testing.T) {
srv := requireSharedThea(t)
srv := helpers.RequireDefaultThea(t)
t.Parallel()

_, authedClient := srv.NewClientWithRandomUser(t)
Expand All @@ -107,7 +93,7 @@ func TestLogout_BlacklistsTokens(t *testing.T) {
// when 'LogoutAll' is called. Other users active on Thea should
// not be impacted by this.
func TestLogoutAll_BlacklistsAllTokens(t *testing.T) {
srv := requireSharedThea(t)
srv := helpers.RequireDefaultThea(t)
t.Parallel()

assertClientState := func(t *testing.T, client *gen.ClientWithResponses, expectedUser *helpers.TestUser) {
Expand Down

0 comments on commit e49dcb3

Please sign in to comment.