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 }