Add result related tags and fields to http_response (#3814)
This commit is contained in:
committed by
Daniel Nelson
parent
8005883de8
commit
81a93fcddf
@@ -15,6 +15,68 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Receives a list with fields that are expected to be absent
|
||||
func checkAbsentFields(t *testing.T, fields []string, acc testutil.Accumulator) {
|
||||
for _, field := range fields {
|
||||
ok := acc.HasField("http_response", field)
|
||||
require.False(t, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Receives a list with tags that are expected to be absent
|
||||
func checkAbsentTags(t *testing.T, tags []string, acc testutil.Accumulator) {
|
||||
for _, tag := range tags {
|
||||
ok := acc.HasTag("http_response", tag)
|
||||
require.False(t, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// Receives a dictionary and with expected fields and their values. If a value is nil, it will only check
|
||||
// that the field exists, but not its contents
|
||||
func checkFields(t *testing.T, fields map[string]interface{}, acc testutil.Accumulator) {
|
||||
for key, field := range fields {
|
||||
switch v := field.(type) {
|
||||
case int:
|
||||
value, ok := acc.IntField("http_response", key)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, field, value)
|
||||
case float64:
|
||||
value, ok := acc.FloatField("http_response", key)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, field, value)
|
||||
case string:
|
||||
value, ok := acc.StringField("http_response", key)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, field, value)
|
||||
case nil:
|
||||
ok := acc.HasField("http_response", key)
|
||||
require.True(t, ok)
|
||||
default:
|
||||
t.Log("Unsupported type for field: ", v)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Receives a dictionary and with expected tags and their values. If a value is nil, it will only check
|
||||
// that the tag exists, but not its contents
|
||||
func checkTags(t *testing.T, tags map[string]interface{}, acc testutil.Accumulator) {
|
||||
for key, tag := range tags {
|
||||
switch v := tag.(type) {
|
||||
case string:
|
||||
ok := acc.HasTag("http_response", key)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, tag, acc.TagValue("http_response", key))
|
||||
case nil:
|
||||
ok := acc.HasTag("http_response", key)
|
||||
require.True(t, ok)
|
||||
default:
|
||||
t.Log("Unsupported type for tag: ", v)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setUpTestMux() http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/redirect", func(w http.ResponseWriter, req *http.Request) {
|
||||
@@ -56,6 +118,24 @@ func setUpTestMux() http.Handler {
|
||||
return mux
|
||||
}
|
||||
|
||||
func checkOutput(t *testing.T, acc testutil.Accumulator, presentFields map[string]interface{}, presentTags map[string]interface{}, absentFields []string, absentTags []string) {
|
||||
if presentFields != nil {
|
||||
checkFields(t, presentFields, acc)
|
||||
}
|
||||
|
||||
if presentTags != nil {
|
||||
checkTags(t, presentTags, acc)
|
||||
}
|
||||
|
||||
if absentFields != nil {
|
||||
checkAbsentFields(t, absentFields, acc)
|
||||
}
|
||||
|
||||
if absentTags != nil {
|
||||
checkAbsentTags(t, absentTags, acc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaders(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
cHeader := r.Header.Get("Content-Type")
|
||||
@@ -78,9 +158,20 @@ func TestHeaders(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields := []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
}
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
@@ -103,12 +194,20 @@ func TestFields(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "success", response_value)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields := []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
}
|
||||
|
||||
func TestRedirects(t *testing.T) {
|
||||
@@ -130,9 +229,20 @@ func TestRedirects(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields := []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
|
||||
h = &HTTPResponse{
|
||||
Address: ts.URL + "/badredirect",
|
||||
@@ -148,11 +258,21 @@ func TestRedirects(t *testing.T) {
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok = acc.IntField("http_response", "http_response_code")
|
||||
require.False(t, ok)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "connection_failed", response_value)
|
||||
expectedFields = map[string]interface{}{
|
||||
"result_type": "connection_failed",
|
||||
"result_code": 3,
|
||||
}
|
||||
expectedTags = map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"result": "connection_failed",
|
||||
}
|
||||
absentFields = []string{"http_response_code", "response_time", "response_string_match"}
|
||||
absentTags := []string{"status_code"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, nil, nil)
|
||||
|
||||
expectedFields = map[string]interface{}{"result_type": "connection_failed"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||
}
|
||||
|
||||
func TestMethod(t *testing.T) {
|
||||
@@ -174,9 +294,20 @@ func TestMethod(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "POST",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields := []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
|
||||
h = &HTTPResponse{
|
||||
Address: ts.URL + "/mustbepostmethod",
|
||||
@@ -192,9 +323,20 @@ func TestMethod(t *testing.T) {
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok = acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusMethodNotAllowed, value)
|
||||
expectedFields = map[string]interface{}{
|
||||
"http_response_code": http.StatusMethodNotAllowed,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags = map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "405",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields = []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
|
||||
//check that lowercase methods work correctly
|
||||
h = &HTTPResponse{
|
||||
@@ -211,9 +353,20 @@ func TestMethod(t *testing.T) {
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok = acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusMethodNotAllowed, value)
|
||||
expectedFields = map[string]interface{}{
|
||||
"http_response_code": http.StatusMethodNotAllowed,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags = map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "head",
|
||||
"status_code": "405",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields = []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
}
|
||||
|
||||
func TestBody(t *testing.T) {
|
||||
@@ -235,9 +388,20 @@ func TestBody(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields := []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
|
||||
h = &HTTPResponse{
|
||||
Address: ts.URL + "/musthaveabody",
|
||||
@@ -252,9 +416,19 @@ func TestBody(t *testing.T) {
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok = acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusBadRequest, value)
|
||||
expectedFields = map[string]interface{}{
|
||||
"http_response_code": http.StatusBadRequest,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
}
|
||||
expectedTags = map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "400",
|
||||
"result": "success",
|
||||
}
|
||||
absentFields = []string{"response_string_match"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, nil)
|
||||
}
|
||||
|
||||
func TestStringMatch(t *testing.T) {
|
||||
@@ -277,17 +451,20 @@ func TestStringMatch(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
value, ok = acc.IntField("http_response", "response_string_match")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, 1, value)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "success", response_value)
|
||||
_, ok = acc.FloatField("http_response", "response_time")
|
||||
require.True(t, ok)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"response_string_match": 1,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, nil, nil)
|
||||
}
|
||||
|
||||
func TestStringMatchJson(t *testing.T) {
|
||||
@@ -310,17 +487,20 @@ func TestStringMatchJson(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
value, ok = acc.IntField("http_response", "response_string_match")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, 1, value)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "success", response_value)
|
||||
_, ok = acc.FloatField("http_response", "response_time")
|
||||
require.True(t, ok)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"response_string_match": 1,
|
||||
"result_type": "success",
|
||||
"result_code": 0,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "success",
|
||||
}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, nil, nil)
|
||||
}
|
||||
|
||||
func TestStringMatchFail(t *testing.T) {
|
||||
@@ -344,17 +524,20 @@ func TestStringMatchFail(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
value, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusOK, value)
|
||||
value, ok = acc.IntField("http_response", "response_string_match")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, 0, value)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "response_string_mismatch", response_value)
|
||||
_, ok = acc.FloatField("http_response", "response_time")
|
||||
require.True(t, ok)
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusOK,
|
||||
"response_string_match": 0,
|
||||
"result_type": "response_string_mismatch",
|
||||
"result_code": 1,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "200",
|
||||
"result": "response_string_mismatch",
|
||||
}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, nil, nil)
|
||||
}
|
||||
|
||||
func TestTimeout(t *testing.T) {
|
||||
@@ -380,11 +563,126 @@ func TestTimeout(t *testing.T) {
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok := acc.IntField("http_response", "http_response_code")
|
||||
require.False(t, ok)
|
||||
response_value, ok := acc.StringField("http_response", "result_type")
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "timeout", response_value)
|
||||
_, ok = acc.FloatField("http_response", "response_time")
|
||||
require.False(t, ok)
|
||||
expectedFields := map[string]interface{}{
|
||||
"result_type": "timeout",
|
||||
"result_code": 4,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"result": "timeout",
|
||||
}
|
||||
absentFields := []string{"http_response_code", "response_time", "response_string_match"}
|
||||
absentTags := []string{"status_code"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||
}
|
||||
|
||||
func TestPluginErrors(t *testing.T) {
|
||||
mux := setUpTestMux()
|
||||
ts := httptest.NewServer(mux)
|
||||
defer ts.Close()
|
||||
|
||||
// Bad regex test. Should return an error and return nothing
|
||||
h := &HTTPResponse{
|
||||
Address: ts.URL + "/good",
|
||||
Body: "{ 'test': 'data'}",
|
||||
Method: "GET",
|
||||
ResponseStringMatch: "bad regex:[[",
|
||||
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||
Headers: map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
FollowRedirects: true,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := h.Gather(&acc)
|
||||
require.Error(t, err)
|
||||
|
||||
absentFields := []string{"http_response_code", "response_time", "response_string_match", "result_type", "result_code"}
|
||||
absentTags := []string{"status_code", "result", "server", "method"}
|
||||
checkOutput(t, acc, nil, nil, absentFields, absentTags)
|
||||
|
||||
// Attempt to read empty body test
|
||||
h = &HTTPResponse{
|
||||
Address: ts.URL + "/redirect",
|
||||
Body: "",
|
||||
Method: "GET",
|
||||
ResponseStringMatch: ".*",
|
||||
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||
FollowRedirects: false,
|
||||
}
|
||||
|
||||
acc = testutil.Accumulator{}
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"http_response_code": http.StatusMovedPermanently,
|
||||
"response_string_match": 0,
|
||||
"result_type": "body_read_error",
|
||||
"result_code": 2,
|
||||
"response_time": nil,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"status_code": "301",
|
||||
"result": "body_read_error",
|
||||
}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, nil, nil)
|
||||
}
|
||||
|
||||
func TestNetworkErrors(t *testing.T) {
|
||||
// DNS error
|
||||
h := &HTTPResponse{
|
||||
Address: "https://nonexistent.nonexistent", // Any non-resolvable URL works here
|
||||
Body: "",
|
||||
Method: "GET",
|
||||
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||
FollowRedirects: false,
|
||||
}
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields := map[string]interface{}{
|
||||
"result_type": "dns_error",
|
||||
"result_code": 5,
|
||||
}
|
||||
expectedTags := map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"result": "dns_error",
|
||||
}
|
||||
absentFields := []string{"http_response_code", "response_time", "response_string_match"}
|
||||
absentTags := []string{"status_code"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||
|
||||
// Connecton failed
|
||||
h = &HTTPResponse{
|
||||
Address: "https://127.127.127.127", // Any non-routable IP works here
|
||||
Body: "",
|
||||
Method: "GET",
|
||||
ResponseTimeout: internal.Duration{Duration: time.Second * 20},
|
||||
FollowRedirects: false,
|
||||
}
|
||||
|
||||
acc = testutil.Accumulator{}
|
||||
err = h.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedFields = map[string]interface{}{
|
||||
"result_type": "connection_failed",
|
||||
"result_code": 3,
|
||||
}
|
||||
expectedTags = map[string]interface{}{
|
||||
"server": nil,
|
||||
"method": "GET",
|
||||
"result": "connection_failed",
|
||||
}
|
||||
absentFields = []string{"http_response_code", "response_time", "response_string_match"}
|
||||
absentTags = []string{"status_code"}
|
||||
checkOutput(t, acc, expectedFields, expectedTags, absentFields, absentTags)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user