github.com/Jeffail/benthos/v3@v3.65.0/internal/integration/cache_test_helpers.go (about)

     1  package integration
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/Jeffail/benthos/v3/lib/config"
    12  	"github.com/Jeffail/benthos/v3/lib/log"
    13  	"github.com/Jeffail/benthos/v3/lib/manager"
    14  	"github.com/Jeffail/benthos/v3/lib/metrics"
    15  	"github.com/Jeffail/benthos/v3/lib/types"
    16  	"github.com/gofrs/uuid"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  	yaml "gopkg.in/yaml.v3"
    20  )
    21  
    22  // CacheTestConfigVars exposes some variables injected into template configs for
    23  // cache unit tests.
    24  type CacheTestConfigVars struct {
    25  	// A unique identifier for separating this test configuration from others.
    26  	// Usually used to access a different topic, consumer group, directory, etc.
    27  	ID string
    28  
    29  	// A Port to use in connector URLs. Allowing tests to override this
    30  	// potentially enables tests that check for faulty connections by bridging.
    31  	Port string
    32  
    33  	// Generic variables.
    34  	Var1 string
    35  }
    36  
    37  // CachePreTestFn is an optional closure to be called before tests are run, this
    38  // is an opportunity to mutate test config variables and mess with the
    39  // environment.
    40  type CachePreTestFn func(t testing.TB, ctx context.Context, testID string, vars *CacheTestConfigVars)
    41  
    42  type cacheTestEnvironment struct {
    43  	configTemplate string
    44  	configVars     CacheTestConfigVars
    45  
    46  	preTest CachePreTestFn
    47  
    48  	timeout time.Duration
    49  	ctx     context.Context
    50  	log     log.Modular
    51  	stats   metrics.Type
    52  }
    53  
    54  func newCacheTestEnvironment(t *testing.T, confTemplate string) cacheTestEnvironment {
    55  	t.Helper()
    56  
    57  	u4, err := uuid.NewV4()
    58  	require.NoError(t, err)
    59  
    60  	return cacheTestEnvironment{
    61  		configTemplate: confTemplate,
    62  		configVars: CacheTestConfigVars{
    63  			ID: u4.String(),
    64  		},
    65  		timeout: time.Second * 90,
    66  		ctx:     context.Background(),
    67  		log:     log.Noop(),
    68  		stats:   metrics.Noop(),
    69  	}
    70  }
    71  
    72  func (e cacheTestEnvironment) RenderConfig() string {
    73  	return strings.NewReplacer(
    74  		"$ID", e.configVars.ID,
    75  		"$PORT", e.configVars.Port,
    76  		"$VAR1", e.configVars.Var1,
    77  	).Replace(e.configTemplate)
    78  }
    79  
    80  //------------------------------------------------------------------------------
    81  
    82  // CacheTestOptFunc is an opt func for customizing the behaviour of cache tests,
    83  // these are useful for things that are integration environment specific, such
    84  // as the port of the service being interacted with.
    85  type CacheTestOptFunc func(*cacheTestEnvironment)
    86  
    87  // CacheTestOptTimeout describes an optional timeout spanning the entirety of
    88  // the test suite.
    89  func CacheTestOptTimeout(timeout time.Duration) CacheTestOptFunc {
    90  	return func(env *cacheTestEnvironment) {
    91  		env.timeout = timeout
    92  	}
    93  }
    94  
    95  // CacheTestOptLogging allows components to log with the given log level. This
    96  // is useful for diagnosing issues.
    97  func CacheTestOptLogging(level string) CacheTestOptFunc {
    98  	return func(env *cacheTestEnvironment) {
    99  		logConf := log.NewConfig()
   100  		logConf.LogLevel = level
   101  		env.log = log.New(os.Stdout, logConf)
   102  	}
   103  }
   104  
   105  // CacheTestOptPort defines the port of the integration service.
   106  func CacheTestOptPort(port string) CacheTestOptFunc {
   107  	return func(env *cacheTestEnvironment) {
   108  		env.configVars.Port = port
   109  	}
   110  }
   111  
   112  // CacheTestOptVarOne sets an arbitrary variable for the test that can be
   113  // injected into templated configs.
   114  func CacheTestOptVarOne(v string) CacheTestOptFunc {
   115  	return func(env *cacheTestEnvironment) {
   116  		env.configVars.Var1 = v
   117  	}
   118  }
   119  
   120  // CacheTestOptPreTest adds a closure to be executed before each test.
   121  func CacheTestOptPreTest(fn CachePreTestFn) CacheTestOptFunc {
   122  	return func(env *cacheTestEnvironment) {
   123  		env.preTest = fn
   124  	}
   125  }
   126  
   127  //------------------------------------------------------------------------------
   128  
   129  type cacheTestDefinitionFn func(*testing.T, *cacheTestEnvironment)
   130  
   131  // CacheTestDefinition encompasses a unit test to be executed against an
   132  // integration environment. These tests are generic and can be run against any
   133  // configuration containing an input and an output that are connected.
   134  type CacheTestDefinition struct {
   135  	fn func(*testing.T, *cacheTestEnvironment)
   136  }
   137  
   138  // CacheTestList is a list of cache test definitions that can be run with a
   139  // single template and function args.
   140  type CacheTestList []CacheTestDefinition
   141  
   142  // CacheTests creates a list of tests from variadic arguments.
   143  func CacheTests(tests ...CacheTestDefinition) CacheTestList {
   144  	return tests
   145  }
   146  
   147  // Run all the tests against a config template. Tests are run in parallel.
   148  func (i CacheTestList) Run(t *testing.T, configTemplate string, opts ...CacheTestOptFunc) {
   149  	for _, test := range i {
   150  		env := newCacheTestEnvironment(t, configTemplate)
   151  		for _, opt := range opts {
   152  			opt(&env)
   153  		}
   154  
   155  		var done func()
   156  		env.ctx, done = context.WithTimeout(env.ctx, env.timeout)
   157  		t.Cleanup(done)
   158  
   159  		if env.preTest != nil {
   160  			env.preTest(t, env.ctx, env.configVars.ID, &env.configVars)
   161  		}
   162  		test.fn(t, &env)
   163  	}
   164  }
   165  
   166  //------------------------------------------------------------------------------
   167  
   168  func namedCacheTest(name string, test cacheTestDefinitionFn) CacheTestDefinition {
   169  	return CacheTestDefinition{
   170  		fn: func(t *testing.T, env *cacheTestEnvironment) {
   171  			t.Run(name, func(t *testing.T) {
   172  				test(t, env)
   173  			})
   174  		},
   175  	}
   176  }
   177  
   178  //------------------------------------------------------------------------------
   179  
   180  func initCache(t *testing.T, env *cacheTestEnvironment) types.Cache {
   181  	t.Helper()
   182  
   183  	confBytes := []byte(env.RenderConfig())
   184  
   185  	s := config.New()
   186  	dec := yaml.NewDecoder(bytes.NewReader(confBytes))
   187  	dec.KnownFields(true)
   188  	require.NoError(t, dec.Decode(&s))
   189  
   190  	lints, err := config.Lint(confBytes, s)
   191  	require.NoError(t, err)
   192  	assert.Empty(t, lints)
   193  
   194  	manager, err := manager.NewV2(s.ResourceConfig, types.NoopMgr(), env.log, env.stats)
   195  	require.NoError(t, err)
   196  
   197  	cache, err := manager.GetCache("testcache")
   198  	require.NoError(t, err)
   199  
   200  	return cache
   201  }
   202  
   203  func closeCache(t *testing.T, cache types.Cache) {
   204  	cache.CloseAsync()
   205  	require.NoError(t, cache.WaitForClose(time.Second*10))
   206  }