Skip to content

Commit

Permalink
This fixes an issue with the type switch that was never able to fall (#…
Browse files Browse the repository at this point in the history
…88)

into cases of []<number>, being <number> a number type such as int,
float32, float64. This is because Go can't type cast slices of
interface{} out right because it's impossible to know the true types of
the slice members beforehand.

Signed-off-by: Tomás Pinho <[email protected]>
  • Loading branch information
tomaspinho authored and arjunrn committed Nov 5, 2019
1 parent f6b2aed commit 0790bc3
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 40 deletions.
51 changes: 27 additions & 24 deletions pkg/collector/json_path_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,38 @@ func (g *JSONPathMetricsGetter) GetMetric(pod *corev1.Pod) (float64, error) {
return float64(res), nil
case float64:
return res, nil
case []int:
return reduce(intsToFloat64s(res), g.aggregator)
case []float32:
return reduce(float32sToFloat64s(res), g.aggregator)
case []float64:
return reduce(res, g.aggregator)
case []interface{}:
s, err := castSlice(res)
if err != nil {
return 0, err
}
return reduce(s, g.aggregator)
default:
return 0, fmt.Errorf("unsupported type %T", res)
}
}

// castSlice takes a slice of interface and returns a slice of float64 if all
// values in slice were castable, else returns an error
func castSlice(in []interface{}) ([]float64, error) {
out := []float64{}

for _, v := range in {
switch v := v.(type) {
case int:
out = append(out, float64(v))
case float32:
out = append(out, float64(v))
case float64:
out = append(out, v)
default:
return nil, fmt.Errorf("slice was returned by JSONPath, but value inside is unsupported: %T", v)
}
}

return out, nil
}

// getPodMetrics returns the content of the pods metrics endpoint.
func getPodMetrics(pod *corev1.Pod, scheme, path string, port int) ([]byte, error) {
if pod.Status.PodIP == "" {
Expand Down Expand Up @@ -144,24 +165,6 @@ func getPodMetrics(pod *corev1.Pod, scheme, path string, port int) ([]byte, erro
return data, nil
}

// intsToFloat64s will convert a slice of int to a slice of float64
func intsToFloat64s(in []int) (out []float64) {
out = []float64{}
for _, v := range in {
out = append(out, float64(v))
}
return
}

// float32sToFloat64s will convert a slice of float32 to a slice of float64
func float32sToFloat64s(in []float32) (out []float64) {
out = []float64{}
for _, v := range in {
out = append(out, float64(v))
}
return
}

// reduce will reduce a slice of numbers given a aggregator function's name. If it's empty or not recognized, an error is returned.
func reduce(values []float64, aggregator string) (float64, error) {
switch aggregator {
Expand Down
30 changes: 14 additions & 16 deletions pkg/collector/json_path_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,22 @@ func TestNewJSONPathMetricsGetter(t *testing.T) {
require.Error(t, err4)
}

func TestIntsToFloat64s(t *testing.T) {
noInts := []int{}
noFloat64s := intsToFloat64s(noInts)
require.Equal(t, []float64{}, noFloat64s)

someInts := []int{1, 2, 3}
someFloat64s := intsToFloat64s(someInts)
require.Equal(t, []float64{1.0, 2.0, 3.0}, someFloat64s)
}
func TestCastSlice(t *testing.T) {
res1, err1 := castSlice([]interface{}{1, 2, 3})
require.NoError(t, err1)
require.Equal(t, []float64{1.0, 2.0, 3.0}, res1)

func TestFloat32sToFloat64s(t *testing.T) {
noFloat32s := []float32{}
noFloat64s := float32sToFloat64s(noFloat32s)
require.Equal(t, []float64{}, noFloat64s)
res2, err2 := castSlice([]interface{}{float32(1.0), float32(2.0), float32(3.0)})
require.NoError(t, err2)
require.Equal(t, []float64{1.0, 2.0, 3.0}, res2)

res3, err3 := castSlice([]interface{}{float64(1.0), float64(2.0), float64(3.0)})
require.NoError(t, err3)
require.Equal(t, []float64{1.0, 2.0, 3.0}, res3)

someFloat32s := []float32{1.0, 2.0, 3.0}
someFloat64s := float32sToFloat64s(someFloat32s)
require.Equal(t, []float64{1.0, 2.0, 3.0}, someFloat64s)
res4, err4 := castSlice([]interface{}{1, 2, "some string"})
require.Errorf(t, err4, "slice was returned by JSONPath, but value inside is unsupported: %T", "string")
require.Equal(t, []float64(nil), res4)
}

func TestReduce(t *testing.T) {
Expand Down

0 comments on commit 0790bc3

Please sign in to comment.