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  }