Files
threshold/internal/clientcache/internal/daemon/testing.go
T
Irena Rindos 2945692bf4 Client cache API paging (#5107)
* internal/clientcache: add -force-reset-schema flag

* clientcache: stream list pages directly to DB

---------

Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
(cherry picked from commit ccea8a4ce53f7b0d1105c1c1e4875e443635d96a)
2024-09-24 14:18:53 +00:00

158 lines
5.8 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package daemon
import (
"context"
"io"
"sync"
"testing"
"github.com/hashicorp/boundary/api/aliases"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/api/sessions"
"github.com/hashicorp/boundary/api/targets"
"github.com/hashicorp/boundary/internal/clientcache/internal/cache"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/require"
)
type TestServer struct {
*CacheServer
dotDir string
cmd Commander
}
// NewTestServer creates a test cache server using reasonable defaults for
// tests. Supports the option WithDebugFlag to enable debug output for sql
func NewTestServer(t *testing.T, cmd Commander, opt ...Option) *TestServer {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
dotDir := t.TempDir()
cfg := &Config{
ContextCancel: cancel,
RefreshInterval: DefaultRefreshInterval,
RecheckSupportInterval: DefaultRecheckSupportInterval,
LogWriter: io.Discard,
DotDirectory: dotDir,
// we need to provide this, otherwise it will open a store in the user's
// home dir. See db.Open(...)
DatabaseUrl: dotDir + "cache.db?_pragma=foreign_keys(1)",
}
s, err := New(ctx, cfg)
require.NoError(t, err)
return &TestServer{
CacheServer: s,
dotDir: dotDir,
cmd: cmd,
}
}
// BaseDotDir returns the base directory in which the daemon socket is
// created.
func (s *TestServer) BaseDotDir() string {
return s.dotDir
}
// Serve runs the cache server. This is a blocking call and returns when the
// server is shutdown or stops for any other reason.
func (s *TestServer) Serve(t *testing.T, opt ...Option) error {
t.Helper()
ctx := context.Background()
t.Cleanup(func() {
s.Shutdown(ctx)
})
return s.CacheServer.Serve(ctx, s.cmd, opt...)
}
func (s *TestServer) AddKeyringToken(t *testing.T, address, keyring, tokenName, tokenId string, atReadFn cache.BoundaryTokenReaderFn) {
t.Helper()
ctx := context.Background()
r, err := cache.NewRepository(ctx, s.CacheServer.store.Load(), &sync.Map{}, s.cmd.ReadTokenFromKeyring, atReadFn)
require.NoError(t, err)
require.NoError(t, r.AddKeyringToken(ctx, address, cache.KeyringToken{
KeyringType: keyring,
TokenName: tokenName,
AuthTokenId: tokenId,
}))
}
// AddResources adds targets, sessions, and aliases to the cache for the
// provided address, token name, and keyring type. They token info must already
// be known to the server.
func (s *TestServer) AddResources(t *testing.T, p *authtokens.AuthToken, alts []*aliases.Alias, tars []*targets.Target, sess []*sessions.Session, atReadFn cache.BoundaryTokenReaderFn) {
t.Helper()
ctx := context.Background()
r, err := cache.NewRepository(ctx, s.CacheServer.store.Load(), &sync.Map{}, s.cmd.ReadTokenFromKeyring, atReadFn)
require.NoError(t, err)
altFn := func(ctx context.Context, _ string, tok, _ string, _ cache.RefreshTokenValue, inPage *aliases.AliasListResult, opt ...cache.Option) (*aliases.AliasListResult, cache.RefreshTokenValue, error) {
if tok != p.Token {
return nil, "", nil
}
return &aliases.AliasListResult{
Items: alts,
}, "addedaliases", nil
}
tarFn := func(ctx context.Context, _ string, tok string, _ cache.RefreshTokenValue, inPage *targets.TargetListResult, opt ...cache.Option) (*targets.TargetListResult, cache.RefreshTokenValue, error) {
if tok != p.Token {
return nil, "", nil
}
return &targets.TargetListResult{
Items: tars,
}, "addedtargets", nil
}
sessFn := func(ctx context.Context, _, tok string, _ cache.RefreshTokenValue, inPage *sessions.SessionListResult, opt ...cache.Option) (*sessions.SessionListResult, cache.RefreshTokenValue, error) {
if tok != p.Token {
return nil, "", nil
}
return &sessions.SessionListResult{
Items: sess,
}, "addedsessions", nil
}
rs, err := cache.NewRefreshService(ctx, r, hclog.NewNullLogger(), 0, 0)
require.NoError(t, err)
require.NoError(t, rs.Refresh(ctx, cache.WithAliasRetrievalFunc(altFn), cache.WithTargetRetrievalFunc(tarFn), cache.WithSessionRetrievalFunc(sessFn)))
}
// AddUnsupportedCachingData provides data in a way that simulates it coming from
// a boundary instance that does not support refresh tokens. Since refresh tokens
// are required for caching, this has the effect of the data not being cached and
// the user being identified as not supported in the cache.
func (s *TestServer) AddUnsupportedCachingData(t *testing.T, p *authtokens.AuthToken, atReadFn cache.BoundaryTokenReaderFn) {
t.Helper()
ctx := context.Background()
r, err := cache.NewRepository(ctx, s.CacheServer.store.Load(), &sync.Map{}, s.cmd.ReadTokenFromKeyring, atReadFn)
require.NoError(t, err)
tarFn := func(ctx context.Context, _, tok string, _ cache.RefreshTokenValue, inPage *targets.TargetListResult, opt ...cache.Option) (*targets.TargetListResult, cache.RefreshTokenValue, error) {
if tok != p.Token {
return &targets.TargetListResult{}, "", nil
}
return &targets.TargetListResult{
Items: []*targets.Target{
{Id: "ttcp_unsupported", Name: "unsupported", Description: "not supported"},
},
}, "", cache.ErrRefreshNotSupported
}
sessFn := func(ctx context.Context, _, tok string, _ cache.RefreshTokenValue, inPage *sessions.SessionListResult, opt ...cache.Option) (*sessions.SessionListResult, cache.RefreshTokenValue, error) {
if tok != p.Token {
return &sessions.SessionListResult{}, "", nil
}
return &sessions.SessionListResult{
Items: []*sessions.Session{
{Id: "s_unsupported"},
},
}, "", cache.ErrRefreshNotSupported
}
rs, err := cache.NewRefreshService(ctx, r, hclog.NewNullLogger(), 0, 0)
require.NoError(t, err)
err = rs.Refresh(ctx, cache.WithTargetRetrievalFunc(tarFn), cache.WithSessionRetrievalFunc(sessFn))
require.ErrorContains(t, err, "not supported for this controller")
}