zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/test/inject/dev.go (about)

     1  //go:build dev
     2  // +build dev
     3  
     4  // This file should be linked only in **development** mode.
     5  
     6  package inject
     7  
     8  import (
     9  	"net/http"
    10  	"sync"
    11  
    12  	zerr "zotregistry.io/zot/errors"
    13  	"zotregistry.io/zot/pkg/log"
    14  )
    15  
    16  func Ok(ok bool) bool {
    17  	if !ok {
    18  		return ok
    19  	}
    20  
    21  	if injectedFailure() {
    22  		return false
    23  	}
    24  
    25  	return true
    26  }
    27  
    28  func Error(err error) error {
    29  	if err != nil {
    30  		return err
    31  	}
    32  
    33  	if injectedFailure() {
    34  		return zerr.ErrInjected
    35  	}
    36  
    37  	return nil
    38  }
    39  
    40  // Used to inject error status codes for coverage purposes.
    41  // -1 will be returned in case of successful failure injection.
    42  func ErrStatusCode(status int) int {
    43  	if !injectedFailure() {
    44  		if status == http.StatusAccepted || status == http.StatusCreated {
    45  			return status
    46  		}
    47  
    48  		return 0
    49  	}
    50  
    51  	return -1
    52  }
    53  
    54  /**
    55   *
    56   * Failure injection infrastructure to cover hard-to-reach code paths.
    57   *
    58   **/
    59  
    60  type inject struct {
    61  	skip int
    62  }
    63  
    64  //nolint:gochecknoglobals // only used by test code
    65  var injMap sync.Map
    66  
    67  func InjectFailure(skip int) bool {
    68  	gid := log.GoroutineID()
    69  	if gid < 0 {
    70  		panic("invalid goroutine id")
    71  	}
    72  
    73  	if _, ok := injMap.Load(gid); ok {
    74  		panic("prior incomplete fault injection")
    75  	}
    76  
    77  	injst := inject{skip: skip}
    78  	injMap.Store(gid, injst)
    79  
    80  	return true
    81  }
    82  
    83  func injectedFailure() bool {
    84  	gid := log.GoroutineID()
    85  
    86  	val, ok := injMap.Load(gid)
    87  	if !ok {
    88  		return false
    89  	}
    90  
    91  	injst, ok := val.(inject)
    92  	if !ok {
    93  		panic("invalid type")
    94  	}
    95  
    96  	if injst.skip == 0 {
    97  		injMap.Delete(gid)
    98  
    99  		return true
   100  	}
   101  
   102  	injst.skip--
   103  	injMap.Store(gid, injst)
   104  
   105  	return false
   106  }