-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Unmarshal JSON numbers as ints where possible
The change modifies the unmarshaling logic to try parsing the numbers in an int64 first, and only on error parse to a float64. In practice, this means that e.g. 1 will become an int64 and 1.0 will become a float64. Fixes #2038. Includes a system test to verify that ticket.
- Loading branch information
Tudor Golubenco
committed
Jul 25, 2016
1 parent
c5c51dd
commit 382997f
Showing
5 changed files
with
152 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,80 @@ | ||
// +build !integration | ||
|
||
package reader | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/elastic/beats/libbeat/common" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestDecodeJSON(t *testing.T) { | ||
func TestUnmarshal(t *testing.T) { | ||
type io struct { | ||
Text string | ||
Config JSONConfig | ||
ExpectedText string | ||
ExpectedMap common.MapStr | ||
Name string | ||
Input string | ||
Output map[string]interface{} | ||
} | ||
|
||
var tests = []io{ | ||
{ | ||
Text: `{"message": "test", "value": 1}`, | ||
Config: JSONConfig{MessageKey: "message"}, | ||
ExpectedText: "test", | ||
ExpectedMap: common.MapStr{"message": "test", "value": float64(1)}, | ||
}, | ||
{ | ||
Text: `{"message": "test", "value": 1}`, | ||
Config: JSONConfig{MessageKey: "message1"}, | ||
ExpectedText: "", | ||
ExpectedMap: common.MapStr{"message": "test", "value": float64(1)}, | ||
}, | ||
{ | ||
Text: `{"message": "test", "value": 1}`, | ||
Config: JSONConfig{MessageKey: "value"}, | ||
ExpectedText: "", | ||
ExpectedMap: common.MapStr{"message": "test", "value": float64(1)}, | ||
tests := []io{ | ||
io{ | ||
Name: "Top level int, float, string, bool", | ||
Input: `{"a": 3, "b": 2.0, "c": "hello", "d": true}`, | ||
Output: map[string]interface{}{ | ||
"a": int64(3), | ||
"b": float64(2), | ||
"c": "hello", | ||
"d": true, | ||
}, | ||
}, | ||
{ | ||
Text: `{"message": "test", "value": "1"}`, | ||
Config: JSONConfig{MessageKey: "value"}, | ||
ExpectedText: "1", | ||
ExpectedMap: common.MapStr{"message": "test", "value": "1"}, | ||
io{ | ||
Name: "Nested objects with ints", | ||
Input: `{"a": 3, "b": {"c": {"d": 5}}}`, | ||
Output: map[string]interface{}{ | ||
"a": int64(3), | ||
"b": map[string]interface{}{ | ||
"c": map[string]interface{}{ | ||
"d": int64(5), | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
// in case of JSON decoding errors, the text is passed as is | ||
Text: `{"message": "test", "value": "`, | ||
Config: JSONConfig{MessageKey: "value"}, | ||
ExpectedText: `{"message": "test", "value": "`, | ||
ExpectedMap: nil, | ||
io{ | ||
Name: "Array of floats", | ||
Input: `{"a": 3, "b": {"c": [4.0, 4.1, 4.2]}}`, | ||
Output: map[string]interface{}{ | ||
"a": int64(3), | ||
"b": map[string]interface{}{ | ||
"c": []interface{}{ | ||
float64(4.0), float64(4.1), float64(4.2), | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
// Add key error helps debugging this | ||
Text: `{"message": "test", "value": "`, | ||
Config: JSONConfig{MessageKey: "value", AddErrorKey: true}, | ||
ExpectedText: `{"message": "test", "value": "`, | ||
ExpectedMap: common.MapStr{"json_error": "Error decoding JSON: unexpected end of JSON input"}, | ||
io{ | ||
Name: "Array of mixed ints and floats", | ||
Input: `{"a": 3, "b": {"c": [4, 4.1, 4.2]}}`, | ||
Output: map[string]interface{}{ | ||
"a": int64(3), | ||
"b": map[string]interface{}{ | ||
"c": []interface{}{ | ||
int64(4), float64(4.1), float64(4.2), | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
// If the text key is not found, put an error | ||
Text: `{"message": "test", "value": "1"}`, | ||
Config: JSONConfig{MessageKey: "hello", AddErrorKey: true}, | ||
ExpectedText: ``, | ||
ExpectedMap: common.MapStr{"message": "test", "value": "1", "json_error": "Key 'hello' not found"}, | ||
}, | ||
{ | ||
// If the text key is found, but not a string, put an error | ||
Text: `{"message": "test", "value": 1}`, | ||
Config: JSONConfig{MessageKey: "value", AddErrorKey: true}, | ||
ExpectedText: ``, | ||
ExpectedMap: common.MapStr{"message": "test", "value": float64(1), "json_error": "Value of key 'value' is not a string"}, | ||
}, | ||
{ | ||
// Without a text key, simple return the json and an empty text | ||
Text: `{"message": "test", "value": 1}`, | ||
Config: JSONConfig{AddErrorKey: true}, | ||
ExpectedText: ``, | ||
ExpectedMap: common.MapStr{"message": "test", "value": float64(1)}, | ||
io{ | ||
Name: "Negative values", | ||
Input: `{"a": -3, "b": -1.0}`, | ||
Output: map[string]interface{}{ | ||
"a": int64(-3), | ||
"b": float64(-1), | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
|
||
var p JSON | ||
p.cfg = &test.Config | ||
text, map_ := p.decodeJSON([]byte(test.Text)) | ||
assert.Equal(t, test.ExpectedText, string(text)) | ||
assert.Equal(t, test.ExpectedMap, map_) | ||
t.Logf("Running test %s", test.Name) | ||
var output map[string]interface{} | ||
err := unmarshal([]byte(test.Input), &output) | ||
assert.NoError(t, err) | ||
assert.Equal(t, test.Output, output) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{"http_user_agent": "ELB-HealthChecker/1.0", "status": 200} | ||
{"http_user_agent": "ELB-HealthChecker/1.0", "status": 404} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters