diff options
author | John Cai <jcai@gitlab.com> | 2020-03-12 04:31:28 +0300 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2020-03-13 21:01:24 +0300 |
commit | 35beb530957158c839265143a744184867b308fc (patch) | |
tree | 43aa618913f0dbb46039ce887f8f2eb33a8e08e6 /internal/praefect/protoregistry | |
parent | f414810c76834bfb3370af0b4b0f46e1f00b58d7 (diff) |
Use praefect server in repository tests
Diffstat (limited to 'internal/praefect/protoregistry')
-rw-r--r-- | internal/praefect/protoregistry/find_oid.go | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/internal/praefect/protoregistry/find_oid.go b/internal/praefect/protoregistry/find_oid.go index 8b73d4943..7d8691fe3 100644 --- a/internal/praefect/protoregistry/find_oid.go +++ b/internal/praefect/protoregistry/find_oid.go @@ -3,6 +3,7 @@ package protoregistry import ( "errors" "fmt" + "math" "reflect" "regexp" "strconv" @@ -22,6 +23,9 @@ var ErrTargetRepoMissing = errors.New("empty Repository") func reflectFindRepoTarget(pbMsg proto.Message, targetOID []int) (*gitalypb.Repository, error) { msgV, e := reflectFindOID(pbMsg, targetOID) if e != nil { + if e == ErrProtoFieldEmpty { + return nil, ErrTargetRepoMissing + } return nil, e } @@ -47,6 +51,9 @@ func reflectFindStorage(pbMsg proto.Message, targetOID []int) (string, error) { return targetRepo, nil } +// ErrProtoFieldEmpty indicates the protobuf field is empty +var ErrProtoFieldEmpty = errors.New("proto field is empty") + // reflectFindOID finds the target repository by using the OID to // navigate the struct tags // Warning: this reflection filled function is full of forbidden dark elf magic @@ -74,7 +81,51 @@ const ( protobufTagRegexFieldGroup = 2 ) +// TODO: This code is copied from the go standard library's reflect package in go 1.13. Once we deprecate support +// for go 1.12, we need to remove this code and call value.isZero directly +func isZero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return math.Float64bits(v.Float()) == 0 + case reflect.Complex64, reflect.Complex128: + c := v.Complex() + return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if !isZero(v.Index(i)) { + return false + } + } + return true + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: + return v.IsNil() + case reflect.String: + return v.Len() == 0 + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if !isZero(v.Field(i)) { + return false + } + } + return true + default: + // This should never happens, but will act as a safeguard for + // later, as a default value doesn't makes sense here. + panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()}) + } +} + func findProtoField(msgV reflect.Value, protoField int) (reflect.Value, error) { + if isZero(msgV) { + return reflect.Value{}, ErrProtoFieldEmpty + } + msgV = reflect.Indirect(msgV) for i := 0; i < msgV.NumField(); i++ { field := msgV.Type().Field(i) @@ -115,6 +166,10 @@ func tryNumberedField(field reflect.StructField, protoField int) (bool, error) { } func tryOneOfField(msgV reflect.Value, field reflect.StructField, protoField int) (reflect.Value, bool) { + if isZero(msgV) { + return reflect.Value{}, false + } + oneOfTag := field.Tag.Get(protobufOneOfTag) if oneOfTag == "" { return reflect.Value{}, false // empty tag means this is not a oneOf field |