From 524fddedb489eb9c74c5fb6aacf3b0e51a63e415 Mon Sep 17 00:00:00 2001
From: Cameron Sparr <cameronsparr@gmail.com>
Date: Wed, 6 Jan 2016 16:11:16 -0700
Subject: [PATCH] 0.3.0 unit tests: exec, httpjson, and haproxy

---
 internal/internal.go                |   2 +-
 plugins/aerospike/aerospike_test.go | 110 ++++++++-------
 plugins/exec/exec_test.go           | 206 +++-------------------------
 plugins/haproxy/haproxy.go          |   2 +-
 plugins/haproxy/haproxy_test.go     | 114 ++++++++-------
 plugins/httpjson/httpjson.go        |   2 +-
 plugins/httpjson/httpjson_test.go   | 145 ++++++++------------
 testutil/accumulator.go             |  31 +++--
 8 files changed, 228 insertions(+), 384 deletions(-)

diff --git a/internal/internal.go b/internal/internal.go
index 93c46780..fc55ba52 100644
--- a/internal/internal.go
+++ b/internal/internal.go
@@ -51,7 +51,7 @@ func (f *JSONFlattener) FlattenJSON(
 		}
 	case float64:
 		f.Fields[fieldname] = t
-	case bool, string, []interface{}:
+	case bool, string, []interface{}, nil:
 		// ignored types
 		return nil
 	default:
diff --git a/plugins/aerospike/aerospike_test.go b/plugins/aerospike/aerospike_test.go
index 1345bdc9..3f4d909a 100644
--- a/plugins/aerospike/aerospike_test.go
+++ b/plugins/aerospike/aerospike_test.go
@@ -1,10 +1,12 @@
 package aerospike
 
 import (
+	"reflect"
+	"testing"
+
 	"github.com/influxdb/telegraf/testutil"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"testing"
 )
 
 func TestAerospikeStatistics(t *testing.T) {
@@ -60,55 +62,57 @@ func TestReadAerospikeStatsNoNamespace(t *testing.T) {
 	acc.AssertContainsTaggedFields(t, "aerospike", fields, tags)
 }
 
-// func TestReadAerospikeStatsNamespace(t *testing.T) {
-// 	var acc testutil.Accumulator
-// 	stats := map[string]string{
-// 		"stat_write_errs": "12345",
-// 		"stat_read_reqs":  "12345",
-// 	}
-// 	readAerospikeStats(stats, &acc, "host1", "test")
-
-// 	tags := map[string]string{
-// 		"aerospike_host": "host1",
-// 		"namespace":      "test",
-// 	}
-// 	for k := range stats {
-// 		assert.True(t, acc.ValidateTaggedValue(k, int64(12345), tags) == nil)
-// 	}
-// }
-
-// func TestAerospikeUnmarshalList(t *testing.T) {
-// 	i := map[string]string{
-// 		"test": "one;two;three",
-// 	}
-
-// 	expected := []string{"one", "two", "three"}
-
-// 	list, err := unmarshalListInfo(i, "test2")
-// 	assert.True(t, err != nil)
-
-// 	list, err = unmarshalListInfo(i, "test")
-// 	assert.True(t, err == nil)
-// 	equal := true
-// 	for ix := range expected {
-// 		if list[ix] != expected[ix] {
-// 			equal = false
-// 			break
-// 		}
-// 	}
-// 	assert.True(t, equal)
-// }
-
-// func TestAerospikeUnmarshalMap(t *testing.T) {
-// 	i := map[string]string{
-// 		"test": "key1=value1;key2=value2",
-// 	}
-
-// 	expected := map[string]string{
-// 		"key1": "value1",
-// 		"key2": "value2",
-// 	}
-// 	m, err := unmarshalMapInfo(i, "test")
-// 	assert.True(t, err == nil)
-// 	assert.True(t, reflect.DeepEqual(m, expected))
-// }
+func TestReadAerospikeStatsNamespace(t *testing.T) {
+	var acc testutil.Accumulator
+	stats := map[string]string{
+		"stat_write_errs": "12345",
+		"stat_read_reqs":  "12345",
+	}
+	readAerospikeStats(stats, &acc, "host1", "test")
+
+	fields := map[string]interface{}{
+		"stat_write_errs": int64(12345),
+		"stat_read_reqs":  int64(12345),
+	}
+	tags := map[string]string{
+		"aerospike_host": "host1",
+		"namespace":      "test",
+	}
+	acc.AssertContainsTaggedFields(t, "aerospike", fields, tags)
+}
+
+func TestAerospikeUnmarshalList(t *testing.T) {
+	i := map[string]string{
+		"test": "one;two;three",
+	}
+
+	expected := []string{"one", "two", "three"}
+
+	list, err := unmarshalListInfo(i, "test2")
+	assert.True(t, err != nil)
+
+	list, err = unmarshalListInfo(i, "test")
+	assert.True(t, err == nil)
+	equal := true
+	for ix := range expected {
+		if list[ix] != expected[ix] {
+			equal = false
+			break
+		}
+	}
+	assert.True(t, equal)
+}
+
+func TestAerospikeUnmarshalMap(t *testing.T) {
+	i := map[string]string{
+		"test": "key1=value1;key2=value2",
+	}
+
+	expected := map[string]string{
+		"key1": "value1",
+		"key2": "value2",
+	}
+	m, err := unmarshalMapInfo(i, "test")
+	assert.True(t, err == nil)
+	assert.True(t, reflect.DeepEqual(m, expected))
+}
diff --git a/plugins/exec/exec_test.go b/plugins/exec/exec_test.go
index 3f0b6f4c..bb94a2fd 100644
--- a/plugins/exec/exec_test.go
+++ b/plugins/exec/exec_test.go
@@ -2,12 +2,11 @@ package exec
 
 import (
 	"fmt"
+	"testing"
+
 	"github.com/influxdb/telegraf/testutil"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	"math"
-	"testing"
-	"time"
 )
 
 // Midnight 9/22/2015
@@ -37,10 +36,6 @@ type runnerMock struct {
 	err error
 }
 
-type clockMock struct {
-	now time.Time
-}
-
 func newRunnerMock(out []byte, err error) Runner {
 	return &runnerMock{
 		out: out,
@@ -48,215 +43,56 @@ func newRunnerMock(out []byte, err error) Runner {
 	}
 }
 
-func (r runnerMock) Run(command *Command) ([]byte, error) {
+func (r runnerMock) Run(e *Exec) ([]byte, error) {
 	if r.err != nil {
 		return nil, r.err
 	}
 	return r.out, nil
 }
 
-func newClockMock(now time.Time) Clock {
-	return &clockMock{now: now}
-}
-
-func (c clockMock) Now() time.Time {
-	return c.now
-}
-
 func TestExec(t *testing.T) {
-	runner := newRunnerMock([]byte(validJson), nil)
-	clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
-	command := Command{
-		Command:   "testcommand arg1",
-		Name:      "mycollector",
-		Interval:  10,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-
 	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&command},
+		runner:  newRunnerMock([]byte(validJson), nil),
+		Command: "testcommand arg1",
+		Name:    "mycollector",
 	}
 
 	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
 	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
 	require.NoError(t, err)
+	assert.Equal(t, acc.NFields(), 4, "non-numeric measurements should be ignored")
 
-	checkFloat := []struct {
-		name  string
-		value float64
-	}{
-		{"mycollector_num_processes", 82},
-		{"mycollector_cpu_used", 8234},
-		{"mycollector_cpu_free", 32},
-		{"mycollector_percent", 0.81},
-	}
-
-	for _, c := range checkFloat {
-		assert.True(t, acc.CheckValue(c.name, c.value))
+	fields := map[string]interface{}{
+		"num_processes": float64(82),
+		"cpu_used":      float64(8234),
+		"cpu_free":      float64(32),
+		"percent":       float64(0.81),
 	}
-
-	assert.Equal(t, deltaPoints, 4, "non-numeric measurements should be ignored")
+	acc.AssertContainsFields(t, "exec_mycollector", fields)
 }
 
 func TestExecMalformed(t *testing.T) {
-	runner := newRunnerMock([]byte(malformedJson), nil)
-	clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
-	command := Command{
-		Command:   "badcommand arg1",
-		Name:      "mycollector",
-		Interval:  10,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-
 	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&command},
+		runner:  newRunnerMock([]byte(malformedJson), nil),
+		Command: "badcommand arg1",
+		Name:    "mycollector",
 	}
 
 	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
 	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
 	require.Error(t, err)
-
-	assert.Equal(t, deltaPoints, 0, "No new points should have been added")
+	assert.Equal(t, acc.NFields(), 0, "No new points should have been added")
 }
 
 func TestCommandError(t *testing.T) {
-	runner := newRunnerMock(nil, fmt.Errorf("exit status code 1"))
-	clock := newClockMock(time.Unix(baseTimeSeconds+20, 0))
-	command := Command{
-		Command:   "badcommand",
-		Name:      "mycollector",
-		Interval:  10,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-
 	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&command},
+		runner:  newRunnerMock(nil, fmt.Errorf("exit status code 1")),
+		Command: "badcommand",
+		Name:    "mycollector",
 	}
 
 	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
 	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
 	require.Error(t, err)
-
-	assert.Equal(t, deltaPoints, 0, "No new points should have been added")
-}
-
-func TestExecNotEnoughTime(t *testing.T) {
-	runner := newRunnerMock([]byte(validJson), nil)
-	clock := newClockMock(time.Unix(baseTimeSeconds+5, 0))
-	command := Command{
-		Command:   "testcommand arg1",
-		Name:      "mycollector",
-		Interval:  10,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-
-	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&command},
-	}
-
-	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
-	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
-	require.NoError(t, err)
-
-	assert.Equal(t, deltaPoints, 0, "No new points should have been added")
-}
-
-func TestExecUninitializedLastRunAt(t *testing.T) {
-	runner := newRunnerMock([]byte(validJson), nil)
-	clock := newClockMock(time.Unix(baseTimeSeconds, 0))
-	command := Command{
-		Command:  "testcommand arg1",
-		Name:     "mycollector",
-		Interval: math.MaxInt32,
-		// Uninitialized lastRunAt should default to time.Unix(0, 0), so this should
-		// run no matter what the interval is
-	}
-
-	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&command},
-	}
-
-	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
-	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
-	require.NoError(t, err)
-
-	checkFloat := []struct {
-		name  string
-		value float64
-	}{
-		{"mycollector_num_processes", 82},
-		{"mycollector_cpu_used", 8234},
-		{"mycollector_cpu_free", 32},
-		{"mycollector_percent", 0.81},
-	}
-
-	for _, c := range checkFloat {
-		assert.True(t, acc.CheckValue(c.name, c.value))
-	}
-
-	assert.Equal(t, deltaPoints, 4, "non-numeric measurements should be ignored")
-}
-func TestExecOneNotEnoughTimeAndOneEnoughTime(t *testing.T) {
-	runner := newRunnerMock([]byte(validJson), nil)
-	clock := newClockMock(time.Unix(baseTimeSeconds+5, 0))
-	notEnoughTimeCommand := Command{
-		Command:   "testcommand arg1",
-		Name:      "mycollector",
-		Interval:  10,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-	enoughTimeCommand := Command{
-		Command:   "testcommand arg1",
-		Name:      "mycollector",
-		Interval:  3,
-		lastRunAt: time.Unix(baseTimeSeconds, 0),
-	}
-
-	e := &Exec{
-		runner:   runner,
-		clock:    clock,
-		Commands: []*Command{&notEnoughTimeCommand, &enoughTimeCommand},
-	}
-
-	var acc testutil.Accumulator
-	initialPoints := len(acc.Points)
-	err := e.Gather(&acc)
-	deltaPoints := len(acc.Points) - initialPoints
-	require.NoError(t, err)
-
-	checkFloat := []struct {
-		name  string
-		value float64
-	}{
-		{"mycollector_num_processes", 82},
-		{"mycollector_cpu_used", 8234},
-		{"mycollector_cpu_free", 32},
-		{"mycollector_percent", 0.81},
-	}
-
-	for _, c := range checkFloat {
-		assert.True(t, acc.CheckValue(c.name, c.value))
-	}
-
-	assert.Equal(t, deltaPoints, 4, "Only one command should have been run")
+	assert.Equal(t, acc.NFields(), 0, "No new points should have been added")
 }
diff --git a/plugins/haproxy/haproxy.go b/plugins/haproxy/haproxy.go
index 2069af24..10f7dab3 100644
--- a/plugins/haproxy/haproxy.go
+++ b/plugins/haproxy/haproxy.go
@@ -91,7 +91,7 @@ var sampleConfig = `
   # If no servers are specified, then default to 127.0.0.1:1936
   servers = ["http://myhaproxy.com:1936", "http://anotherhaproxy.com:1936"]
   # Or you can also use local socket(not work yet)
-  # servers = ["socket:/run/haproxy/admin.sock"]
+  # servers = ["socket://run/haproxy/admin.sock"]
 `
 
 func (r *haproxy) SampleConfig() string {
diff --git a/plugins/haproxy/haproxy_test.go b/plugins/haproxy/haproxy_test.go
index 6f07d34d..e514bc7a 100644
--- a/plugins/haproxy/haproxy_test.go
+++ b/plugins/haproxy/haproxy_test.go
@@ -47,52 +47,39 @@ func TestHaproxyGeneratesMetricsWithAuthentication(t *testing.T) {
 		"sv":     "host0",
 	}
 
-	assert.NoError(t, acc.ValidateTaggedValue("stot", uint64(171014), tags))
-
-	checkInt := []struct {
-		name  string
-		value uint64
-	}{
-
-		{"qmax", 81},
-		{"scur", 288},
-		{"smax", 713},
-		{"bin", 5557055817},
-		{"bout", 24096715169},
-		{"dreq", 1102},
-		{"dresp", 80},
-		{"ereq", 95740},
-		{"econ", 0},
-		{"eresp", 0},
-		{"wretr", 17},
-		{"wredis", 19},
-		{"active_servers", 1},
-		{"backup_servers", 0},
-		{"downtime", 0},
-		{"throttle", 13},
-		{"lbtot", 114},
-		{"rate", 18},
-		{"rate_max", 102},
-		{"check_duration", 1},
-		{"http_response.1xx", 0},
-		{"http_response.2xx", 1314093},
-		{"http_response.3xx", 537036},
-		{"http_response.4xx", 123452},
-		{"http_response.5xx", 11966},
-		{"req_rate", 35},
-		{"req_rate_max", 140},
-		{"req_tot", 1987928},
-		{"cli_abort", 0},
-		{"srv_abort", 0},
-		{"qtime", 0},
-		{"ctime", 2},
-		{"rtime", 23},
-		{"ttime", 545},
-	}
-
-	for _, c := range checkInt {
-		assert.Equal(t, true, acc.CheckValue(c.name, c.value))
+	fields := map[string]interface{}{
+		"active_servers":    uint64(1),
+		"backup_servers":    uint64(0),
+		"bin":               uint64(510913516),
+		"bout":              uint64(2193856571),
+		"check_duration":    uint64(10),
+		"cli_abort":         uint64(73),
+		"ctime":             uint64(2),
+		"downtime":          uint64(0),
+		"dresp":             uint64(0),
+		"econ":              uint64(0),
+		"eresp":             uint64(1),
+		"http_response.1xx": uint64(0),
+		"http_response.2xx": uint64(119534),
+		"http_response.3xx": uint64(48051),
+		"http_response.4xx": uint64(2345),
+		"http_response.5xx": uint64(1056),
+		"lbtot":             uint64(171013),
+		"qcur":              uint64(0),
+		"qmax":              uint64(0),
+		"qtime":             uint64(0),
+		"rate":              uint64(3),
+		"rate_max":          uint64(12),
+		"rtime":             uint64(312),
+		"scur":              uint64(1),
+		"smax":              uint64(32),
+		"srv_abort":         uint64(1),
+		"stot":              uint64(171014),
+		"ttime":             uint64(2341),
+		"wredis":            uint64(0),
+		"wretr":             uint64(1),
 	}
+	acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
 
 	//Here, we should get error because we don't pass authentication data
 	r = &haproxy{
@@ -124,10 +111,39 @@ func TestHaproxyGeneratesMetricsWithoutAuthentication(t *testing.T) {
 		"sv":     "host0",
 	}
 
-	assert.NoError(t, acc.ValidateTaggedValue("stot", uint64(171014), tags))
-	assert.NoError(t, acc.ValidateTaggedValue("scur", uint64(1), tags))
-	assert.NoError(t, acc.ValidateTaggedValue("rate", uint64(3), tags))
-	assert.Equal(t, true, acc.CheckValue("bin", uint64(5557055817)))
+	fields := map[string]interface{}{
+		"active_servers":    uint64(1),
+		"backup_servers":    uint64(0),
+		"bin":               uint64(510913516),
+		"bout":              uint64(2193856571),
+		"check_duration":    uint64(10),
+		"cli_abort":         uint64(73),
+		"ctime":             uint64(2),
+		"downtime":          uint64(0),
+		"dresp":             uint64(0),
+		"econ":              uint64(0),
+		"eresp":             uint64(1),
+		"http_response.1xx": uint64(0),
+		"http_response.2xx": uint64(119534),
+		"http_response.3xx": uint64(48051),
+		"http_response.4xx": uint64(2345),
+		"http_response.5xx": uint64(1056),
+		"lbtot":             uint64(171013),
+		"qcur":              uint64(0),
+		"qmax":              uint64(0),
+		"qtime":             uint64(0),
+		"rate":              uint64(3),
+		"rate_max":          uint64(12),
+		"rtime":             uint64(312),
+		"scur":              uint64(1),
+		"smax":              uint64(32),
+		"srv_abort":         uint64(1),
+		"stot":              uint64(171014),
+		"ttime":             uint64(2341),
+		"wredis":            uint64(0),
+		"wretr":             uint64(1),
+	}
+	acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
 }
 
 //When not passing server config, we default to localhost
diff --git a/plugins/httpjson/httpjson.go b/plugins/httpjson/httpjson.go
index 40a771a9..9da0f63d 100644
--- a/plugins/httpjson/httpjson.go
+++ b/plugins/httpjson/httpjson.go
@@ -153,7 +153,7 @@ func (h *HttpJson) gatherServer(
 	} else {
 		msrmnt_name = "httpjson_" + h.Name
 	}
-	acc.AddFields(msrmnt_name, f.Fields, nil)
+	acc.AddFields(msrmnt_name, f.Fields, tags)
 	return nil
 }
 
diff --git a/plugins/httpjson/httpjson_test.go b/plugins/httpjson/httpjson_test.go
index 8f9bfe3a..7e9ffd33 100644
--- a/plugins/httpjson/httpjson_test.go
+++ b/plugins/httpjson/httpjson_test.go
@@ -1,7 +1,6 @@
 package httpjson
 
 import (
-	"fmt"
 	"io/ioutil"
 	"net/http"
 	"strings"
@@ -35,6 +34,11 @@ const validJSONTags = `
 		"build": "123"
 	}`
 
+var expectedFields = map[string]interface{}{
+	"parent_child": float64(3),
+	"integer":      float64(4),
+}
+
 const invalidJSON = "I don't think this is JSON"
 
 const empty = ""
@@ -76,37 +80,36 @@ func (c mockHTTPClient) MakeRequest(req *http.Request) (*http.Response, error) {
 //
 // Returns:
 //     *HttpJson: Pointer to an HttpJson object that uses the generated mock HTTP client
-func genMockHttpJson(response string, statusCode int) *HttpJson {
-	return &HttpJson{
-		client: mockHTTPClient{responseBody: response, statusCode: statusCode},
-		Services: []Service{
-			Service{
-				Servers: []string{
-					"http://server1.example.com/metrics/",
-					"http://server2.example.com/metrics/",
-				},
-				Name:   "my_webapp",
-				Method: "GET",
-				Parameters: map[string]string{
-					"httpParam1": "12",
-					"httpParam2": "the second parameter",
-				},
+func genMockHttpJson(response string, statusCode int) []*HttpJson {
+	return []*HttpJson{
+		&HttpJson{
+			client: mockHTTPClient{responseBody: response, statusCode: statusCode},
+			Servers: []string{
+				"http://server1.example.com/metrics/",
+				"http://server2.example.com/metrics/",
 			},
-			Service{
-				Servers: []string{
-					"http://server3.example.com/metrics/",
-					"http://server4.example.com/metrics/",
-				},
-				Name:   "other_webapp",
-				Method: "POST",
-				Parameters: map[string]string{
-					"httpParam1": "12",
-					"httpParam2": "the second parameter",
-				},
-				TagKeys: []string{
-					"role",
-					"build",
-				},
+			Name:   "my_webapp",
+			Method: "GET",
+			Parameters: map[string]string{
+				"httpParam1": "12",
+				"httpParam2": "the second parameter",
+			},
+		},
+		&HttpJson{
+			client: mockHTTPClient{responseBody: response, statusCode: statusCode},
+			Servers: []string{
+				"http://server3.example.com/metrics/",
+				"http://server4.example.com/metrics/",
+			},
+			Name:   "other_webapp",
+			Method: "POST",
+			Parameters: map[string]string{
+				"httpParam1": "12",
+				"httpParam2": "the second parameter",
+			},
+			TagKeys: []string{
+				"role",
+				"build",
 			},
 		},
 	}
@@ -116,28 +119,15 @@ func genMockHttpJson(response string, statusCode int) *HttpJson {
 func TestHttpJson200(t *testing.T) {
 	httpjson := genMockHttpJson(validJSON, 200)
 
-	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
-	require.NoError(t, err)
-
-	assert.Equal(t, 8, len(acc.Points))
-
-	for _, service := range httpjson.Services {
+	for _, service := range httpjson {
+		var acc testutil.Accumulator
+		err := service.Gather(&acc)
+		require.NoError(t, err)
+		assert.Equal(t, 4, acc.NFields())
 		for _, srv := range service.Servers {
-			require.NoError(t,
-				acc.ValidateTaggedValue(
-					fmt.Sprintf("%s_parent_child", service.Name),
-					3.0,
-					map[string]string{"server": srv},
-				),
-			)
-			require.NoError(t,
-				acc.ValidateTaggedValue(
-					fmt.Sprintf("%s_integer", service.Name),
-					4.0,
-					map[string]string{"server": srv},
-				),
-			)
+			tags := map[string]string{"server": srv}
+			mname := "httpjson_" + service.Name
+			acc.AssertContainsTaggedFields(t, mname, expectedFields, tags)
 		}
 	}
 }
@@ -147,28 +137,22 @@ func TestHttpJson500(t *testing.T) {
 	httpjson := genMockHttpJson(validJSON, 500)
 
 	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
+	err := httpjson[0].Gather(&acc)
 
 	assert.NotNil(t, err)
-	// 4 error lines for (2 urls) * (2 services)
-	assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
-	assert.Equal(t, 0, len(acc.Points))
+	assert.Equal(t, 0, acc.NFields())
 }
 
 // Test response to HTTP 405
 func TestHttpJsonBadMethod(t *testing.T) {
 	httpjson := genMockHttpJson(validJSON, 200)
-	httpjson.Services[0].Method = "NOT_A_REAL_METHOD"
+	httpjson[0].Method = "NOT_A_REAL_METHOD"
 
 	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
+	err := httpjson[0].Gather(&acc)
 
 	assert.NotNil(t, err)
-	// 2 error lines for (2 urls) * (1 falied service)
-	assert.Equal(t, len(strings.Split(err.Error(), "\n")), 2)
-
-	// (2 measurements) * (2 servers) * (1 successful service)
-	assert.Equal(t, 4, len(acc.Points))
+	assert.Equal(t, 0, acc.NFields())
 }
 
 // Test response to malformed JSON
@@ -176,12 +160,10 @@ func TestHttpJsonBadJson(t *testing.T) {
 	httpjson := genMockHttpJson(invalidJSON, 200)
 
 	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
+	err := httpjson[0].Gather(&acc)
 
 	assert.NotNil(t, err)
-	// 4 error lines for (2 urls) * (2 services)
-	assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
-	assert.Equal(t, 0, len(acc.Points))
+	assert.Equal(t, 0, acc.NFields())
 }
 
 // Test response to empty string as response objectgT
@@ -189,34 +171,27 @@ func TestHttpJsonEmptyResponse(t *testing.T) {
 	httpjson := genMockHttpJson(empty, 200)
 
 	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
+	err := httpjson[0].Gather(&acc)
 
 	assert.NotNil(t, err)
-	// 4 error lines for (2 urls) * (2 services)
-	assert.Equal(t, len(strings.Split(err.Error(), "\n")), 4)
-	assert.Equal(t, 0, len(acc.Points))
+	assert.Equal(t, 0, acc.NFields())
 }
 
 // Test that the proper values are ignored or collected
 func TestHttpJson200Tags(t *testing.T) {
 	httpjson := genMockHttpJson(validJSONTags, 200)
 
-	var acc testutil.Accumulator
-	err := httpjson.Gather(&acc)
-	require.NoError(t, err)
-
-	assert.Equal(t, 4, len(acc.Points))
-
-	for _, service := range httpjson.Services {
+	for _, service := range httpjson {
 		if service.Name == "other_webapp" {
+			var acc testutil.Accumulator
+			err := service.Gather(&acc)
+			require.NoError(t, err)
+			assert.Equal(t, 2, acc.NFields())
 			for _, srv := range service.Servers {
-				require.NoError(t,
-					acc.ValidateTaggedValue(
-						fmt.Sprintf("%s_value", service.Name),
-						15.0,
-						map[string]string{"server": srv, "role": "master", "build": "123"},
-					),
-				)
+				tags := map[string]string{"server": srv, "role": "master", "build": "123"}
+				fields := map[string]interface{}{"value": float64(15)}
+				mname := "httpjson_" + service.Name
+				acc.AssertContainsTaggedFields(t, mname, fields, tags)
 			}
 		}
 	}
diff --git a/testutil/accumulator.go b/testutil/accumulator.go
index 3262db16..3800fef4 100644
--- a/testutil/accumulator.go
+++ b/testutil/accumulator.go
@@ -1,6 +1,7 @@
 package testutil
 
 import (
+	"encoding/json"
 	"fmt"
 	"reflect"
 	"sync"
@@ -25,7 +26,9 @@ func (p *Point) String() string {
 // Accumulator defines a mocked out accumulator
 type Accumulator struct {
 	sync.Mutex
+
 	Points []*Point
+	debug  bool
 }
 
 // Add adds a measurement point to the accumulator
@@ -59,6 +62,14 @@ func (a *Accumulator) AddFields(
 		t = time.Now()
 	}
 
+	if a.debug {
+		pretty, _ := json.MarshalIndent(fields, "", "  ")
+		prettyTags, _ := json.MarshalIndent(tags, "", "  ")
+		msg := fmt.Sprintf("Adding Measurement [%s]\nFields:%s\nTags:%s\n",
+			measurement, string(pretty), string(prettyTags))
+		fmt.Print(msg)
+	}
+
 	p := &Point{
 		Measurement: measurement,
 		Fields:      fields,
@@ -66,10 +77,7 @@ func (a *Accumulator) AddFields(
 		Time:        t,
 	}
 
-	a.Points = append(
-		a.Points,
-		p,
-	)
+	a.Points = append(a.Points, p)
 }
 
 func (a *Accumulator) SetDefaultTags(tags map[string]string) {
@@ -91,11 +99,12 @@ func (a *Accumulator) SetPrefix(prefix string) {
 
 func (a *Accumulator) Debug() bool {
 	// stub for implementing Accumulator interface.
-	return true
+	return a.debug
 }
 
 func (a *Accumulator) SetDebug(debug bool) {
 	// stub for implementing Accumulator interface.
+	a.debug = debug
 }
 
 // Get gets the specified measurement point from the accumulator
@@ -134,8 +143,10 @@ func (a *Accumulator) AssertContainsTaggedFields(
 
 		if p.Measurement == measurement {
 			if !reflect.DeepEqual(fields, p.Fields) {
-				msg := fmt.Sprintf("Actual:\n %v (%T) \nExpected:\n %v (%T)",
-					p.Fields, p.Fields, fields, fields)
+				pActual, _ := json.MarshalIndent(p.Fields, "", "  ")
+				pExp, _ := json.MarshalIndent(fields, "", "  ")
+				msg := fmt.Sprintf("Actual:\n%s\n(%T) \nExpected:\n%s\n(%T)",
+					string(pActual), p.Fields, string(pExp), fields)
 				assert.Fail(t, msg)
 			}
 			return
@@ -153,8 +164,10 @@ func (a *Accumulator) AssertContainsFields(
 	for _, p := range a.Points {
 		if p.Measurement == measurement {
 			if !reflect.DeepEqual(fields, p.Fields) {
-				msg := fmt.Sprintf("Actual:\n %v (%T) \nExpected:\n %v (%T)",
-					p.Fields, p.Fields, fields, fields)
+				pActual, _ := json.MarshalIndent(p.Fields, "", "  ")
+				pExp, _ := json.MarshalIndent(fields, "", "  ")
+				msg := fmt.Sprintf("Actual:\n%s\n(%T) \nExpected:\n%s\n(%T)",
+					string(pActual), p.Fields, string(pExp), fields)
 				assert.Fail(t, msg)
 			}
 			return
-- 
GitLab