github.com/blend/go-sdk@v1.20220411.3/testutil/suite.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package testutil 9 10 import ( 11 "context" 12 "os" 13 "testing" 14 15 "github.com/blend/go-sdk/ex" 16 "github.com/blend/go-sdk/logger" 17 ) 18 19 // FailureCodes 20 const ( 21 SuiteFailureTests = 1 22 SuiteFailureBefore = 2 23 SuiteFailureAfter = 3 24 ) 25 26 // New returns a new test suite. 27 func New(m *testing.M, opts ...Option) *Suite { 28 s := Suite{ 29 M: m, 30 } 31 for _, opt := range opts { 32 opt(&s) 33 } 34 return &s 35 } 36 37 // Option is a mutator for a test suite. 38 type Option func(*Suite) 39 40 // SuiteAction is a step that can be run either before or after package tests. 41 type SuiteAction func(context.Context) error 42 43 // Suite is a set of before and after actions for a given package tests. 44 type Suite struct { 45 M *testing.M 46 Log logger.Log 47 Before []SuiteAction 48 After []SuiteAction 49 } 50 51 // Run runs tests and calls os.Exit(...) with the exit code. 52 func (s Suite) Run() { 53 os.Exit(s.RunCode()) 54 } 55 56 // RunCode runs the suite and returns an exit code. 57 // 58 // It is used by `.Run()`, which will os.Exit(...) this code. 59 func (s Suite) RunCode() (code int) { 60 ctx := context.Background() 61 if s.Log != nil { 62 ctx = logger.WithLogger(ctx, s.Log) 63 } 64 var err error 65 for _, before := range s.Before { 66 if err = executeSafe(ctx, before); err != nil { 67 logger.MaybeFatalf(s.Log, "error during setup steps: %+v", err) 68 code = SuiteFailureBefore 69 return 70 } 71 } 72 defer func() { 73 for _, after := range s.After { 74 if err = executeSafe(ctx, after); err != nil { 75 logger.MaybeFatalf(s.Log, "error during cleanup steps: %+v", err) 76 code = SuiteFailureAfter 77 return 78 } 79 } 80 }() 81 if s.M != nil { 82 code = s.M.Run() 83 } 84 return 85 } 86 87 func executeSafe(ctx context.Context, action func(context.Context) error) (err error) { 88 defer func() { 89 if r := recover(); r != nil { 90 err = ex.New(r) 91 } 92 }() 93 err = action(ctx) 94 return 95 }