Skip to content

Commit

Permalink
dynamic/msgregistry: Add typed errors for lookups (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
johanbrandhorst committed Mar 2, 2021
1 parent a735446 commit 8255811
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 8 deletions.
30 changes: 24 additions & 6 deletions dynamic/msgregistry/message_registry.go
Expand Up @@ -22,6 +22,21 @@ import (

const googleApisDomain = "type.googleapis.com"

// ErrUnexpectedType is returned if the URL that was requested
// resolved to an enum instead of a message, or vice versa.
type ErrUnexpectedType struct {
URL string
ShouldBeEnum bool
}

func (e *ErrUnexpectedType) Error() string {
msg := "wanted message, got enum"
if e.ShouldBeEnum {
msg = "wanted enum, got message"
}
return fmt.Sprintf("type for URL %q is the wrong type: %s", e.URL, msg)
}

// MessageRegistry is a registry that maps URLs to message types. It allows for marshalling
// and unmarshalling Any types to and from dynamic messages.
type MessageRegistry struct {
Expand Down Expand Up @@ -165,7 +180,8 @@ func (r *MessageRegistry) addMessageTypesLocked(baseUrl string, msgs []*desc.Mes

// FindMessageTypeByUrl finds a message descriptor for the type at the given URL. It may
// return nil if the registry is empty and cannot resolve unknown URLs. If an error occurs
// while resolving the URL, it is returned.
// while resolving the URL, it is returned. If the resolved type is a enum, ErrUnexpectedType
// is returned.
func (r *MessageRegistry) FindMessageTypeByUrl(url string) (*desc.MessageDescriptor, error) {
md, err := r.getRegisteredMessageTypeByUrl(url)
if err != nil {
Expand All @@ -188,8 +204,9 @@ func (r *MessageRegistry) getRegisteredMessageTypeByUrl(url string) (*desc.Messa
if m != nil {
if md, ok := m.(*desc.MessageDescriptor); ok {
return md, nil
} else {
return nil, fmt.Errorf("type for URL %v is the wrong type: wanted message, got enum", url)
}
return nil, &ErrUnexpectedType{
URL: url,
}
}
}
Expand All @@ -207,7 +224,7 @@ func (r *MessageRegistry) getRegisteredMessageTypeByUrl(url string) (*desc.Messa

// FindEnumTypeByUrl finds an enum descriptor for the type at the given URL. It may return nil
// if the registry is empty and cannot resolve unknown URLs. If an error occurs while resolving
// the URL, it is returned.
// the URL, it is returned. If the resolved type is a message, ErrUnexpectedType is returned.
func (r *MessageRegistry) FindEnumTypeByUrl(url string) (*desc.EnumDescriptor, error) {
ed, err := r.getRegisteredEnumTypeByUrl(url)
if err != nil {
Expand Down Expand Up @@ -236,8 +253,9 @@ func (r *MessageRegistry) getRegisteredEnumTypeByUrl(url string) (*desc.EnumDesc
if m != nil {
if ed, ok := m.(*desc.EnumDescriptor); ok {
return ed, nil
} else {
return nil, fmt.Errorf("type for URL %v is the wrong type: wanted enum, got message", url)
}
return nil, &ErrUnexpectedType{
URL: url,
}
}
return nil, nil
Expand Down
6 changes: 4 additions & 2 deletions dynamic/msgregistry/message_registry_test.go
Expand Up @@ -59,9 +59,11 @@ func TestMessageRegistry_LookupTypes(t *testing.T) {

// wrong type
_, err = mr.FindMessageTypeByUrl("foo.bar/google.protobuf.FieldDescriptorProto.Type")
testutil.Require(t, err != nil && strings.Contains(err.Error(), "wanted message, got enum"))
_, ok := err.(*ErrUnexpectedType)
testutil.Require(t, ok)
_, err = mr.FindEnumTypeByUrl("foo.bar/google.protobuf.DescriptorProto")
testutil.Require(t, err != nil && strings.Contains(err.Error(), "wanted enum, got message"))
_, ok = err.(*ErrUnexpectedType)
testutil.Require(t, ok)

// unmarshal any successfully finds the registered type
b, err := proto.Marshal(md.AsProto())
Expand Down

0 comments on commit 8255811

Please sign in to comment.