attributes: print typed nil values instead of panic (#6574)

Co-authored-by: Easwar Swaminathan <easwars@google.com>
This commit is contained in:
Haixin Chen 2023-09-23 03:09:02 +08:00 committed by GitHub
parent fe0dc2275d
commit 58e2f2b105
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 3 deletions

View File

@ -121,13 +121,13 @@ func (a *Attributes) String() string {
return sb.String()
}
func str(x any) string {
func str(x any) (s string) {
if v, ok := x.(fmt.Stringer); ok {
return v.String()
return fmt.Sprint(v)
} else if v, ok := x.(string); ok {
return v
}
return fmt.Sprintf("<%p>", x)
return fmt.Sprintf("%#v", x)
}
// MarshalJSON helps implement the json.Marshaler interface, thereby rendering

View File

@ -34,6 +34,14 @@ func (s stringVal) Equal(o any) bool {
return ok && s.s == os.s
}
type stringerVal struct {
s string
}
func (s stringerVal) String() string {
return s.s
}
func ExampleAttributes() {
type keyOne struct{}
type keyTwo struct{}
@ -57,6 +65,36 @@ func ExampleAttributes_WithValue() {
// Key two: {two}
}
func ExampleAttributes_String() {
type key struct{}
var typedNil *stringerVal
a1 := attributes.New(key{}, typedNil) // typed nil implements [fmt.Stringer]
a2 := attributes.New(key{}, (*stringerVal)(nil)) // typed nil implements [fmt.Stringer]
a3 := attributes.New(key{}, (*stringVal)(nil)) // typed nil not implements [fmt.Stringer]
a4 := attributes.New(key{}, nil) // untyped nil
a5 := attributes.New(key{}, 1)
a6 := attributes.New(key{}, stringerVal{s: "two"})
a7 := attributes.New(key{}, stringVal{s: "two"})
a8 := attributes.New(1, true)
fmt.Println("a1:", a1.String())
fmt.Println("a2:", a2.String())
fmt.Println("a3:", a3.String())
fmt.Println("a4:", a4.String())
fmt.Println("a5:", a5.String())
fmt.Println("a6:", a6.String())
fmt.Println("a7:", a7.String())
fmt.Println("a8:", a8.String())
// Output:
// a1: {"attributes_test.key{}": "<nil>" }
// a2: {"attributes_test.key{}": "<nil>" }
// a3: {"attributes_test.key{}": "(*attributes_test.stringVal)(nil)" }
// a4: {"attributes_test.key{}": "<nil>" }
// a5: {"attributes_test.key{}": "1" }
// a6: {"attributes_test.key{}": "two" }
// a7: {"attributes_test.key{}": "attributes_test.stringVal{s:\"two\"}" }
// a8: {"1": "true" }
}
// Test that two attributes with the same content are Equal.
func TestEqual(t *testing.T) {
type keyOne struct{}

View File

@ -142,3 +142,23 @@ func (s) TestResolverAddressesToEndpoints(t *testing.T) {
t.Fatalf("timed out waiting for endpoints")
}
}
// Test ensures that there is no panic if the attributes within
// resolver.State.Addresses contains a typed-nil value.
func (s) TestResolverAddressesWithTypedNilAttribute(t *testing.T) {
r := manual.NewBuilderWithScheme(t.Name())
resolver.Register(r)
addrAttr := attributes.New("typed_nil", (*stringerVal)(nil))
r.InitialState(resolver.State{Addresses: []resolver.Address{{Addr: "addr1", Attributes: addrAttr}}})
cc, err := Dial(r.Scheme()+":///", WithTransportCredentials(insecure.NewCredentials()), WithResolvers(r))
if err != nil {
t.Fatalf("Unexpected error dialing: %v", err)
}
defer cc.Close()
}
type stringerVal struct{ s string }
func (s stringerVal) String() string { return s.s }