Skip to content

Commit

Permalink
fix number transformation from json files in heartbeat (elastic#13348)
Browse files Browse the repository at this point in the history
Prior to this patch heartbeat could not check JSON responses for numeric values correctly because they were incorrectly being cast to the wrong type for comparison.

(cherry picked from commit fb62c66)
  • Loading branch information
osherdp authored and andrewvc committed Sep 2, 2019
1 parent 653e3b7 commit 122b83b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

- Fix NPEs / resource leaks when executing config checks. {pull}11165[11165]
- Fix duplicated IPs on `mode: all` monitors. {pull}12458[12458]
- Fix integer comparison on JSON responses. {pull}13348[13348]

*Journalbeat*

Expand Down
7 changes: 6 additions & 1 deletion heartbeat/monitors/active/http/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
pkgerrors "github.com/pkg/errors"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/common/jsontransform"
"github.com/elastic/beats/libbeat/common/match"
"github.com/elastic/beats/libbeat/conditions"
)
Expand Down Expand Up @@ -148,13 +149,17 @@ func checkJSON(checks []*jsonResponseCheck) (RespCheck, error) {

return func(r *http.Response) error {
decoded := &common.MapStr{}
err := json.NewDecoder(r.Body).Decode(decoded)
decoder := json.NewDecoder(r.Body)
decoder.UseNumber()
err := decoder.Decode(decoded)

if err != nil {
body, _ := ioutil.ReadAll(r.Body)
return pkgerrors.Wrapf(err, "could not parse JSON for body check with condition. Source: %s", body)
}

jsontransform.TransformNumbers(*decoded)

var errorDescs []string
for _, compiledCheck := range compiledChecks {
ok := compiledCheck.condition.Check(decoded)
Expand Down
66 changes: 66 additions & 0 deletions heartbeat/monitors/active/http/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,69 @@ func TestCheckJson(t *testing.T) {
}

}

func TestCheckJsonWithIntegerComparison(t *testing.T) {
fooBazEqualsBar := common.MustNewConfigFrom(map[string]interface{}{"equals": map[string]interface{}{"foo": 1}})
fooBazEqualsBarConf := &conditions.Config{}
err := fooBazEqualsBar.Unpack(fooBazEqualsBarConf)
require.NoError(t, err)

fooBazEqualsBarDesc := "foo equals 1"

var tests = []struct {
description string
body string
condDesc string
condConf *conditions.Config
result bool
}{
{
"positive match",
"{\"foo\": 1}",
fooBazEqualsBarDesc,
fooBazEqualsBarConf,
true,
},
{
"Negative match",
"{\"foo\": 2}",
fooBazEqualsBarDesc,
fooBazEqualsBarConf,
false,
},
{
"Negative match",
"{\"foo\": \"some string\"}",
fooBazEqualsBarDesc,
fooBazEqualsBarConf,
false,
},
}

for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, test.body)
}))
defer ts.Close()

res, err := http.Get(ts.URL)
if err != nil {
log.Fatal(err)
}

checker, err := checkJSON([]*jsonResponseCheck{{test.condDesc, test.condConf}})
require.NoError(t, err)
checkRes := checker(res)

if result := checkRes == nil; result != test.result {
if test.result {
t.Fatalf("Expected condition: '%s' to match body: %s. got: %s", test.condDesc, test.body, checkRes)
} else {
t.Fatalf("Did not expect condition: '%s' to match body: %s. got: %s", test.condDesc, test.body, checkRes)
}
}
})
}

}
37 changes: 37 additions & 0 deletions heartbeat/tests/system/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,43 @@ def test_http_json(self, expected_status, body):
finally:
server.shutdown()

@parameterized.expand([
('{"foo": "bar"}', {"foo": "bar"}),
('{"foo": true}', {"foo": True},),
('{"foo": 3}', {"foo": 3},),
])
def test_json_simple_comparisons(self, body, comparison):
"""
Test JSON response with simple straight-forward comparisons
"""
server = self.start_server(body, 200)
try:
self.render_config_template(
monitors=[{
"type": "http",
"urls": ["http://localhost:{}".format(server.server_port)],
"check_response_json": [{
"description": body,
"condition": {
"equals": comparison
}
}]
}]
)

try:
proc = self.start_beat()
self.wait_until(lambda: self.log_contains("heartbeat is running"))

self.wait_until(
lambda: self.output_has(lines=1))
finally:
proc.check_kill_and_wait()

self.assert_last_status("up")
finally:
server.shutdown()

@parameterized.expand([
(lambda server: "localhost:{}".format(server.server_port), "up"),
# This IP is reserved in IPv4
Expand Down

0 comments on commit 122b83b

Please sign in to comment.