Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions heartbeat/hbtest/hbtestutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ func SizedResponseHandler(bytes int) http.HandlerFunc {
)
}

func CustomResponseHandler(body []byte, status int) http.HandlerFunc {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
w.Write(body)
},
)
}

// RedirectHandler redirects the paths at the keys in the redirectingPaths map to the locations in their values.
// For paths not in the redirectingPaths map it returns a 200 response with the given body.
func RedirectHandler(redirectingPaths map[string]string, body string) http.HandlerFunc {
Expand Down
106 changes: 106 additions & 0 deletions heartbeat/monitors/active/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,112 @@ func TestLargeResponse(t *testing.T) {
)
}

func TestJsonBody(t *testing.T) {
type testCase struct {
name string
responseBody string
condition common.MapStr
expectedErrMsg string
expectedContentType string
}

testCases := []testCase{
{
"simple match",
"{\"foo\": \"bar\"}",
common.MapStr{
"equals": common.MapStr{"foo": "bar"},
},
"",
"application/json",
},
{
"mismatch",
"{\"foo\": \"bar\"}",
common.MapStr{
"equals": common.MapStr{"baz": "bot"},
},
"JSON body did not match",
"application/json",
},
{
"invalid json",
"notjson",
common.MapStr{
"equals": common.MapStr{"foo": "bar"},
},
"could not parse JSON",
"text/plain; charset=utf-8",
},
{
"complex type match json",
"{\"number\": 3, \"bool\": true}",
common.MapStr{
"equals": common.MapStr{"number": 3, "bool": true},
},
"",
"application/json",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
server := httptest.NewServer(hbtest.CustomResponseHandler([]byte(tc.responseBody), 200))
defer server.Close()

configSrc := map[string]interface{}{
"hosts": server.URL,
"timeout": "1s",
"response.include_body": "never",
"check.response.json": []common.MapStr{
{
"description": "myJsonCheck",
"condition": tc.condition,
},
},
}

config, err := common.NewConfigFrom(configSrc)
require.NoError(t, err)

p, err := create("largeresp", config)
require.NoError(t, err)

sched, _ := schedule.Parse("@every 1s")
job := wrappers.WrapCommon(p.Jobs, stdfields.StdMonitorFields{ID: "test", Type: "http", Schedule: sched, Timeout: 1})[0]

event := &beat.Event{}
_, err = job(event)
require.NoError(t, err)

if tc.expectedErrMsg == "" {
testslike.Test(
t,
lookslike.Strict(lookslike.Compose(
hbtest.BaseChecks("127.0.0.1", "up", "http"),
hbtest.RespondingTCPChecks(),
hbtest.SummaryChecks(1, 0),
respondingHTTPChecks(server.URL, tc.expectedContentType, 200),
)),
event.Fields,
)
} else {
testslike.Test(
t,
lookslike.Strict(lookslike.Compose(
hbtest.BaseChecks("127.0.0.1", "down", "http"),
hbtest.RespondingTCPChecks(),
hbtest.SummaryChecks(0, 1),
hbtest.ErrorChecks(tc.expectedErrMsg, "validate"),
respondingHTTPChecks(server.URL, tc.expectedContentType, 200),
)),
event.Fields,
)
}
})
}
}

func runHTTPSServerCheck(
t *testing.T,
server *httptest.Server,
Expand Down
82 changes: 0 additions & 82 deletions heartbeat/tests/system/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,88 +90,6 @@ def test_http_delayed(self):
finally:
server.shutdown()

@parameterized.expand([
("up", '{"foo": {"baz": "bar"}}'),
("down", '{"foo": "unexpected"}'),
("down", 'notjson'),
])
def test_http_json(self, expected_status, body):
"""
Test JSON response checks
"""
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": "foo equals bar",
"condition": {
"equals": {"foo": {"baz": "bar"}}
}
}]
}]
)

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(expected_status)
if expected_status == "down":
self.assertEqual(self.last_output_line()["http.response.body.content"], body)
if body == "notjson":
self.assertEqual(self.last_output_line()["http.response.mime_type"], "text/plain; charset=utf-8")
else:
self.assertEqual(self.last_output_line()["http.response.mime_type"], "application/json")
else:
assert "http.response.body.content" not in self.last_output_line()
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