Repository: go-kratos/kratos
Pull request #1130 (2021-06-30 09:02:35)

feat: add int/int32/Stringer support when get atomicValue
When the variable type is `int`/`int32`, I think we can also try to convert it to the desired type, as the `int` is sometimes the default type for many conversions (such as Unmarshal), and if it is `string` we can also try to assert whether implements the `String` method.

Further more, is it reasonable to convert any other two types that is convertible (such as boolean `true` to int `1`)?

Please point out if there is anything I have not considered. Thanks in advance.


Patch:
diff --git a/config/value.go b/config/value.go
index 52ed86b4..bc96aa05 100644
--- a/config/value.go
+++ b/config/value.go
@@ -37,13 +37,17 @@ func (v *atomicValue) Bool() (bool, error) {
 	switch val := v.Load().(type) {
 	case bool:
 		return val, nil
-	case int64, float64, string:
+	case int, int32, int64, float64, string:
 		return strconv.ParseBool(fmt.Sprint(val))
 	}
 	return false, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
 }
 func (v *atomicValue) Int() (int64, error) {
 	switch val := v.Load().(type) {
+	case int:
+		return int64(val), nil
+	case int32:
+		return int64(val), nil
 	case int64:
 		return int64(val), nil
 	case float64:
@@ -57,6 +61,10 @@ func (v *atomicValue) Float() (float64, error) {
 	switch val := v.Load().(type) {
 	case float64:
 		return float64(val), nil
+	case int:
+		return float64(val), nil
+	case int32:
+		return float64(val), nil
 	case int64:
 		return float64(val), nil
 	case string:
@@ -68,8 +76,12 @@ func (v *atomicValue) String() (string, error) {
 	switch val := v.Load().(type) {
 	case string:
 		return val, nil
-	case bool, int64, float64:
+	case bool, int, int32, int64, float64:
 		return fmt.Sprint(val), nil
+	default:
+		if s, ok := val.(fmt.Stringer); ok {
+			return s.String(), nil
+		}
 	}
 	return "", fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
 }
diff --git a/transport/http/server.go b/transport/http/server.go
index 9d63b8c6..1c5bc960 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -228,5 +228,5 @@ func (s *Server) Start(ctx context.Context) error {
 // Stop stop the HTTP server.
 func (s *Server) Stop(ctx context.Context) error {
 	s.log.Info("[HTTP] server stopping")
-	return s.Shutdown(context.Background())
+	return s.Shutdown(ctx)
 }


Test patch:
diff --git a/config/value_test.go b/config/value_test.go
index 4219bdf8..87f18091 100644
--- a/config/value_test.go
+++ b/config/value_test.go
@@ -1,6 +1,7 @@
 package config
 
 import (
+	"fmt"
 	"testing"
 	"time"
 
@@ -9,7 +10,7 @@ import (
 
 func Test_atomicValue_Bool(t *testing.T) {
 	var vlist []interface{}
-	vlist = []interface{}{"1", "t", "T", "true", "TRUE", "True", true}
+	vlist = []interface{}{"1", "t", "T", "true", "TRUE", "True", true, 1, int32(1)}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -18,7 +19,7 @@ func Test_atomicValue_Bool(t *testing.T) {
 		assert.True(t, b, b)
 	}
 
-	vlist = []interface{}{"0", "f", "F", "false", "FALSE", "False", false}
+	vlist = []interface{}{"0", "f", "F", "false", "FALSE", "False", false, 0, int32(0)}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -27,7 +28,7 @@ func Test_atomicValue_Bool(t *testing.T) {
 		assert.False(t, b, b)
 	}
 
-	vlist = []interface{}{int32(1), 1, uint16(1), "bbb", "-1"}
+	vlist = []interface{}{uint16(1), "bbb", "-1"}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -38,7 +39,7 @@ func Test_atomicValue_Bool(t *testing.T) {
 
 func Test_atomicValue_Int(t *testing.T) {
 	var vlist []interface{}
-	vlist = []interface{}{"123123", float64(123123), int64(123123)}
+	vlist = []interface{}{"123123", float64(123123), int64(123123), int32(123123), 123123}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -47,7 +48,7 @@ func Test_atomicValue_Int(t *testing.T) {
 		assert.Equal(t, int64(123123), b, b)
 	}
 
-	vlist = []interface{}{int32(1123123), 123131, uint16(1), "bbb", "-x1"}
+	vlist = []interface{}{uint16(1), "bbb", "-x1", true}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -67,7 +68,7 @@ func Test_atomicValue_Float(t *testing.T) {
 		assert.Equal(t, float64(123123.1), b, b)
 	}
 
-	vlist = []interface{}{float32(1123123), 123131, uint16(1), "bbb", "-x1"}
+	vlist = []interface{}{float32(1123123), uint16(1), "bbb", "-x1"}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -76,9 +77,18 @@ func Test_atomicValue_Float(t *testing.T) {
 	}
 }
 
+type ts struct {
+	Name string
+	Age  int
+}
+
+func (t ts) String() string {
+	return fmt.Sprintf("%s%d", t.Name, t.Age)
+}
+
 func Test_atomicValue_String(t *testing.T) {
 	var vlist []interface{}
-	vlist = []interface{}{"1", float64(1), int64(1)}
+	vlist = []interface{}{"1", float64(1), int64(1), 1, int64(1)}
 	for _, x := range vlist {
 		v := atomicValue{}
 		v.Store(x)
@@ -92,6 +102,15 @@ func Test_atomicValue_String(t *testing.T) {
 	b, err := v.String()
 	assert.NoError(t, err, b)
 	assert.Equal(t, "true", b, b)
+
+	v = atomicValue{}
+	v.Store(ts{
+		Name: "test",
+		Age:  10,
+	})
+	b, err = v.String()
+	assert.NoError(t, err, b)
+	assert.Equal(t, "test10", b, "test Stringer should be equal")
 }
 
 func Test_atomicValue_Duration(t *testing.T) {