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 }