diff --git a/heartbeat/monitors/active/http/http_test.go b/heartbeat/monitors/active/http/http_test.go index 4822dc0cb68..bd5bd1f5dd4 100644 --- a/heartbeat/monitors/active/http/http_test.go +++ b/heartbeat/monitors/active/http/http_test.go @@ -38,7 +38,6 @@ import ( "github.com/elastic/beats/libbeat/common/file" "github.com/elastic/beats/libbeat/common/mapval" btesting "github.com/elastic/beats/libbeat/testing" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) func testRequest(t *testing.T, testURL string) *beat.Event { @@ -192,7 +191,7 @@ func TestUpStatuses(t *testing.T) { t.Run(fmt.Sprintf("Test OK HTTP status %d", status), func(t *testing.T) { server, event := checkServer(t, hbtest.HelloWorldHandler(status)) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks("127.0.0.1", "up", "http"), @@ -212,7 +211,7 @@ func TestDownStatuses(t *testing.T) { t.Run(fmt.Sprintf("test down status %d", status), func(t *testing.T) { server, event := checkServer(t, hbtest.HelloWorldHandler(status)) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks("127.0.0.1", "down", "http"), @@ -249,7 +248,7 @@ func TestLargeResponse(t *testing.T) { _, err = job(event) require.NoError(t, err) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks("127.0.0.1", "up", "http"), @@ -282,7 +281,7 @@ func runHTTPSServerCheck( event := testTLSRequest(t, server.URL, mergedExtraConfig) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks("127.0.0.1", "up", "http"), @@ -348,7 +347,7 @@ func TestConnRefusedJob(t *testing.T) { event := testRequest(t, url) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks(ip, "down", "http"), @@ -370,7 +369,7 @@ func TestUnreachableJob(t *testing.T) { event := testRequest(t, url) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks(ip, "down", "http"), diff --git a/heartbeat/monitors/active/tcp/tcp_test.go b/heartbeat/monitors/active/tcp/tcp_test.go index 36c6c79f3de..fc857a298b5 100644 --- a/heartbeat/monitors/active/tcp/tcp_test.go +++ b/heartbeat/monitors/active/tcp/tcp_test.go @@ -35,7 +35,6 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/mapval" btesting "github.com/elastic/beats/libbeat/testing" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) func testTCPCheck(t *testing.T, host string, port uint16) *beat.Event { @@ -102,7 +101,7 @@ func TestUpEndpointJob(t *testing.T) { event := testTCPCheck(t, "localhost", port) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.BaseChecks("127.0.0.1", "up", "tcp"), @@ -145,7 +144,7 @@ func TestTLSConnection(t *testing.T) { defer os.Remove(certFile.Name()) event := testTLSTCPCheck(t, ip, port, certFile.Name()) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( hbtest.TLSChecks(0, 0, cert), @@ -166,7 +165,7 @@ func TestConnectionRefusedEndpointJob(t *testing.T) { event := testTCPCheck(t, ip, port) dialErr := fmt.Sprintf("dial tcp %s:%d", ip, port) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( tcpMonitorChecks(ip, ip, port, "down"), @@ -184,7 +183,7 @@ func TestUnreachableEndpointJob(t *testing.T) { event := testTCPCheck(t, ip, port) dialErr := fmt.Sprintf("dial tcp %s:%d", ip, port) - mapvaltest.Test( + mapval.Test( t, mapval.Strict(mapval.Compose( tcpMonitorChecks(ip, ip, port, "down"), diff --git a/heartbeat/monitors/jobs/job.go b/heartbeat/monitors/jobs/job.go index 4c9b9db43f5..efa38739401 100644 --- a/heartbeat/monitors/jobs/job.go +++ b/heartbeat/monitors/jobs/job.go @@ -17,7 +17,9 @@ package jobs -import "github.com/elastic/beats/libbeat/beat" +import ( + "github.com/elastic/beats/libbeat/beat" +) // A Job represents a unit of execution, and may return multiple continuation jobs. type Job func(event *beat.Event) ([]Job, error) @@ -46,6 +48,24 @@ func WrapAll(jobs []Job, wrappers ...JobWrapper) []Job { return wrapped } +// JobWrapperFactory can be used to created new instances of JobWrappers. +type JobWrapperFactory func() JobWrapper + +// WrapAllSeparately wraps the given jobs using the given JobWrapperFactory instances. +// This enables us to use a different JobWrapper for the jobs passed in, but recursively apply +// the same wrapper to their children. +func WrapAllSeparately(jobs []Job, factories ...JobWrapperFactory) []Job { + var wrapped []Job + for _, j := range jobs { + for _, factory := range factories { + wrapper := factory() + j = Wrap(j, wrapper) + } + wrapped = append(wrapped, j) + } + return wrapped +} + // Wrap wraps the given Job and also any continuations with the given JobWrapper. func Wrap(job Job, wrapper JobWrapper) Job { return func(event *beat.Event) ([]Job, error) { diff --git a/heartbeat/monitors/jobs/job_test.go b/heartbeat/monitors/jobs/job_test.go index c26077ba28d..6a3e06223a0 100644 --- a/heartbeat/monitors/jobs/job_test.go +++ b/heartbeat/monitors/jobs/job_test.go @@ -26,7 +26,6 @@ import ( "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/mapval" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) func TestWrapAll(t *testing.T) { @@ -117,7 +116,7 @@ func TestWrapAll(t *testing.T) { fr := results[idx].Fields validator := mapval.Strict(mapval.MustCompile(rf)) - mapvaltest.Test(t, validator, fr) + mapval.Test(t, validator, fr) } }) } diff --git a/heartbeat/monitors/monitor_test.go b/heartbeat/monitors/monitor_test.go index bc459278e71..ce86bb16371 100644 --- a/heartbeat/monitors/monitor_test.go +++ b/heartbeat/monitors/monitor_test.go @@ -21,11 +21,12 @@ import ( "testing" "time" + "github.com/elastic/beats/libbeat/common/mapval" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/elastic/beats/heartbeat/scheduler" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) func TestMonitor(t *testing.T) { @@ -58,7 +59,7 @@ func TestMonitor(t *testing.T) { pcClient.Close() for _, event := range pcClient.Publishes() { - mapvaltest.Test(t, mockEventMonitorValidator(""), event.Fields) + mapval.Test(t, mockEventMonitorValidator(""), event.Fields) } } else { // Let's yield this goroutine so we don't spin diff --git a/heartbeat/monitors/wrappers/monitors.go b/heartbeat/monitors/wrappers/monitors.go index 3d67f36808b..ad05d22c5e9 100644 --- a/heartbeat/monitors/wrappers/monitors.go +++ b/heartbeat/monitors/wrappers/monitors.go @@ -23,38 +23,61 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/mitchellh/hashstructure" + "github.com/pkg/errors" "github.com/elastic/beats/heartbeat/eventext" "github.com/elastic/beats/heartbeat/look" "github.com/elastic/beats/heartbeat/monitors/jobs" "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" ) // WrapCommon applies the common wrappers that all monitor jobs get. func WrapCommon(js []jobs.Job, id string, name string, typ string) []jobs.Job { - return jobs.WrapAll( - js, - addMonitorStatus, - addMonitorDuration, - addMonitorMeta(id, name, typ), - makeAddSummary(id, uint16(len(js))), - ) + return jobs.WrapAllSeparately( + jobs.WrapAll( + js, + addMonitorStatus, + addMonitorDuration, + ), func() jobs.JobWrapper { + return addMonitorMeta(id, name, typ, len(js) > 1) + }, func() jobs.JobWrapper { + return makeAddSummary() + }) } // addMonitorMeta adds the id, name, and type fields to the monitor. -func addMonitorMeta(id string, name string, typ string) jobs.JobWrapper { +func addMonitorMeta(id string, name string, typ string, isMulti bool) jobs.JobWrapper { return func(job jobs.Job) jobs.Job { - return WithFields( - common.MapStr{ - "monitor": common.MapStr{ - "id": id, - "name": name, - "type": typ, + return func(event *beat.Event) ([]jobs.Job, error) { + cont, e := job(event) + thisID := id + + if isMulti { + url, err := event.GetValue("url.full") + if err != nil { + logp.Error(errors.Wrap(err, "Mandatory url.full key missing!")) + url = "n/a" + } + urlHash, _ := hashstructure.Hash(url, nil) + thisID = fmt.Sprintf("%s-%x", id, urlHash) + } + + eventext.MergeEventFields( + event, + common.MapStr{ + "monitor": common.MapStr{ + "id": thisID, + "name": name, + "type": typ, + }, }, - }, - job, - ) + ) + + return cont, e + } } } @@ -99,7 +122,7 @@ func addMonitorDuration(job jobs.Job) jobs.Job { } // makeAddSummary summarizes the job, adding the `summary` field to the last event emitted. -func makeAddSummary(id string, numJobs uint16) jobs.JobWrapper { +func makeAddSummary() jobs.JobWrapper { // This is a tricky method. The way this works is that we track the state across jobs in the // state struct here. state := struct { @@ -114,7 +137,7 @@ func makeAddSummary(id string, numJobs uint16) jobs.JobWrapper { } // Note this is not threadsafe, must be called from a mutex resetState := func() { - state.remaining = numJobs + state.remaining = 1 state.up = 0 state.down = 0 state.generation++ diff --git a/heartbeat/monitors/wrappers/monitors_test.go b/heartbeat/monitors/wrappers/monitors_test.go index b6a150d2103..00755b4c6e2 100644 --- a/heartbeat/monitors/wrappers/monitors_test.go +++ b/heartbeat/monitors/wrappers/monitors_test.go @@ -19,152 +19,213 @@ package wrappers import ( "fmt" + "net/url" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/elastic/beats/heartbeat/eventext" "github.com/elastic/beats/heartbeat/monitors/jobs" "github.com/elastic/beats/libbeat/beat" "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/mapval" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) -func TestWrapCommon(t *testing.T) { - var simpleJob jobs.Job = func(event *beat.Event) ([]jobs.Job, error) { - eventext.MergeEventFields(event, common.MapStr{"simple": "job"}) - return nil, nil - } +type fields struct { + id string + name string + typ string +} - var errorJob jobs.Job = func(event *beat.Event) ([]jobs.Job, error) { - return nil, fmt.Errorf("myerror") - } +type testDef struct { + name string + fields fields + jobs []jobs.Job + want []mapval.Validator +} - var contJob jobs.Job = func(event *beat.Event) ([]jobs.Job, error) { - eventext.MergeEventFields(event, common.MapStr{"cont": "1st"}) - return []jobs.Job{ - func(event *beat.Event) ([]jobs.Job, error) { - eventext.MergeEventFields(event, common.MapStr{"cont": "2nd"}) - return nil, nil - }, - }, nil - } +func testCommonWrap(t *testing.T, tt testDef) { + t.Run(tt.name, func(t *testing.T) { + wrapped := WrapCommon(tt.jobs, tt.fields.id, tt.fields.name, tt.fields.typ) + + results, err := jobs.ExecJobsAndConts(t, wrapped) + assert.NoError(t, err) - type fields struct { - id string - name string - typ string + for idx, r := range results { + t.Run(fmt.Sprintf("result at index %d", idx), func(t *testing.T) { + mapval.Test(t, mapval.Strict(tt.want[idx]), r.Fields) + }) + } + }) +} + +func TestSimpleJob(t *testing.T) { + fields := fields{"myid", "myname", "mytyp"} + testCommonWrap(t, testDef{ + "simple", + fields, + []jobs.Job{makeURLJob(t, "tcp://foo.com:80")}, + []mapval.Validator{ + mapval.Compose( + urlValidator(t, "tcp://foo.com:80"), + mapval.MustCompile(mapval.Map{ + "monitor": mapval.Map{ + "duration.us": mapval.IsDuration, + "id": fields.id, + "name": fields.name, + "type": fields.typ, + "status": "up", + "check_group": mapval.IsString, + }, + }), + summaryValidator(1, 0), + )}, + }) +} + +func TestErrorJob(t *testing.T) { + fields := fields{"myid", "myname", "mytyp"} + + errorJob := func(event *beat.Event) ([]jobs.Job, error) { + return nil, fmt.Errorf("myerror") } - testFields := fields{"myid", "myname", "mytyp"} - commonFieldsValidator := func(f fields, status string) mapval.Validator { - return mapval.MustCompile(mapval.Map{ + errorJobValidator := mapval.Compose( + mapval.MustCompile(mapval.Map{"error": mapval.Map{"message": "myerror", "type": "io"}}), + mapval.MustCompile(mapval.Map{ "monitor": mapval.Map{ "duration.us": mapval.IsDuration, - "id": f.id, - "name": f.name, - "type": f.typ, - "status": status, + "id": fields.id, + "name": fields.name, + "type": fields.typ, + "status": "down", "check_group": mapval.IsString, }, - }) - } + }), + ) - // This duplicates hbtest.SummaryChecks to avoid an import cycle. - // It could be refactored out, but it just isn't worth it. - summaryValidator := func(up int, down int) mapval.Validator { - return mapval.MustCompile(mapval.Map{ - "summary": mapval.Map{ - "up": uint16(up), - "down": uint16(down), - }, - }) + testCommonWrap(t, testDef{ + "job error", + fields, + []jobs.Job{errorJob}, + []mapval.Validator{ + mapval.Compose( + errorJobValidator, + summaryValidator(0, 1), + )}, + }) +} + +func TestMultiJobNoConts(t *testing.T) { + fields := fields{"myid", "myname", "mytyp"} + + uniqScope := mapval.ScopedIsUnique() + + validator := func(u string) mapval.Validator { + return mapval.Compose( + urlValidator(t, u), + mapval.MustCompile(mapval.Map{ + "monitor": mapval.Map{ + "duration.us": mapval.IsDuration, + "id": uniqScope.IsUniqueTo("id"), + "name": fields.name, + "type": fields.typ, + "status": "up", + "check_group": uniqScope.IsUniqueTo("check_group"), + }, + }), + summaryValidator(1, 0), + ) } - simpleJobValidator := mapval.Compose( - mapval.MustCompile(mapval.Map{"simple": "job"}), - commonFieldsValidator(testFields, "up"), - ) + testCommonWrap(t, testDef{ + "multi-job", + fields, + []jobs.Job{makeURLJob(t, "http://foo.com"), makeURLJob(t, "http://bar.com")}, + []mapval.Validator{validator("http://foo.com"), validator("http://bar.com")}, + }) +} - errorJobValidator := mapval.Compose( - mapval.MustCompile(mapval.Map{"error": mapval.Map{"message": "myerror", "type": "io"}}), - commonFieldsValidator(testFields, "down"), - ) +func TestMultiJobConts(t *testing.T) { + fields := fields{"myid", "myname", "mytyp"} + + uniqScope := mapval.ScopedIsUnique() + + makeContJob := func(t *testing.T, u string) jobs.Job { + return func(event *beat.Event) ([]jobs.Job, error) { + eventext.MergeEventFields(event, common.MapStr{"cont": "1st"}) + u, err := url.Parse(u) + require.NoError(t, err) + eventext.MergeEventFields(event, common.MapStr{"url": URLFields(u)}) + return []jobs.Job{ + func(event *beat.Event) ([]jobs.Job, error) { + eventext.MergeEventFields(event, common.MapStr{"cont": "2nd"}) + eventext.MergeEventFields(event, common.MapStr{"url": URLFields(u)}) + return nil, nil + }, + }, nil + } + } - contJobValidator := func(msg string) mapval.Validator { + contJobValidator := func(u string, msg string) mapval.Validator { return mapval.Compose( + urlValidator(t, u), mapval.MustCompile(mapval.Map{"cont": msg}), - commonFieldsValidator(testFields, "up"), + mapval.MustCompile(mapval.Map{ + "monitor": mapval.Map{ + "duration.us": mapval.IsDuration, + "id": uniqScope.IsUniqueTo(u), + "name": fields.name, + "type": fields.typ, + "status": "up", + "check_group": uniqScope.IsUniqueTo(u), + }, + }), ) } - tests := []struct { - name string - fields fields - jobs []jobs.Job - want []mapval.Validator - }{ - { - "simple", - testFields, - []jobs.Job{simpleJob}, - []mapval.Validator{ - mapval.Compose( - simpleJobValidator, - summaryValidator(1, 0), - )}, - }, - { - "job error", - testFields, - []jobs.Job{errorJob}, - []mapval.Validator{ - mapval.Compose( - errorJobValidator, - summaryValidator(0, 1), - )}, - }, - { - "multi-job", - testFields, - []jobs.Job{simpleJob, simpleJob}, - []mapval.Validator{ - simpleJobValidator, - mapval.Compose( - simpleJobValidator, - summaryValidator(2, 0), - ), - }, + testCommonWrap(t, testDef{ + "multi-job-continuations", + fields, + []jobs.Job{makeContJob(t, "http://foo.com"), makeContJob(t, "http://bar.com")}, + []mapval.Validator{ + contJobValidator("http://foo.com", "1st"), + mapval.Compose( + contJobValidator("http://foo.com", "2nd"), + summaryValidator(2, 0), + ), + contJobValidator("http://bar.com", "1st"), + mapval.Compose( + contJobValidator("http://bar.com", "2nd"), + summaryValidator(2, 0), + ), }, - { - "multi-job-continuations", - testFields, - []jobs.Job{contJob, contJob}, - []mapval.Validator{ - contJobValidator("1st"), - contJobValidator("2nd"), - contJobValidator("1st"), - mapval.Compose( - contJobValidator("2nd"), - commonFieldsValidator(testFields, "up"), - summaryValidator(4, 0), - ), - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - wrapped := WrapCommon(tt.jobs, tt.fields.id, tt.fields.name, tt.fields.typ) - - results, err := jobs.ExecJobsAndConts(t, wrapped) - assert.NoError(t, err) - - for idx, r := range results { - t.Run(fmt.Sprintf("result at index %d", idx), func(t *testing.T) { - mapvaltest.Test(t, mapval.Strict(tt.want[idx]), r.Fields) - }) - } - }) + }) +} + +func makeURLJob(t *testing.T, u string) jobs.Job { + parsed, err := url.Parse(u) + require.NoError(t, err) + return func(event *beat.Event) (i []jobs.Job, e error) { + eventext.MergeEventFields(event, common.MapStr{"url": URLFields(parsed)}) + return nil, nil } } + +func urlValidator(t *testing.T, u string) mapval.Validator { + parsed, err := url.Parse(u) + require.NoError(t, err) + return mapval.MustCompile(mapval.Map{"url": mapval.Map(URLFields(parsed))}) +} + +// This duplicates hbtest.SummaryChecks to avoid an import cycle. +// It could be refactored out, but it just isn't worth it. +func summaryValidator(up int, down int) mapval.Validator { + return mapval.MustCompile(mapval.Map{ + "summary": mapval.Map{ + "up": uint16(up), + "down": uint16(down), + }, + }) +} diff --git a/heartbeat/monitors/wrappers/util_test.go b/heartbeat/monitors/wrappers/util_test.go index 573ab1dfebe..ecb1bbeffff 100644 --- a/heartbeat/monitors/wrappers/util_test.go +++ b/heartbeat/monitors/wrappers/util_test.go @@ -25,7 +25,6 @@ import ( "github.com/elastic/beats/libbeat/common" "github.com/elastic/beats/libbeat/common/mapval" - "github.com/elastic/beats/libbeat/testing/mapvaltest" ) func TestURLFields(t *testing.T) { @@ -82,7 +81,7 @@ func TestURLFields(t *testing.T) { require.NoError(t, err) got := URLFields(parsed) - mapvaltest.Test(t, mapval.MustCompile(mapval.Map(tt.want)), got) + mapval.Test(t, mapval.MustCompile(mapval.Map(tt.want)), got) }) } } diff --git a/libbeat/common/mapval/is_defs.go b/libbeat/common/mapval/is_defs.go index d85369d4c95..457e85343dc 100644 --- a/libbeat/common/mapval/is_defs.go +++ b/libbeat/common/mapval/is_defs.go @@ -177,6 +177,34 @@ func IsAny(of ...IsDef) IsDef { }) } +// IsUnique instances are used in multiple spots, flagging a value as being in error if it's seen across invocations. +// To use it, assign IsUnique to a variable, then use that variable multiple times in a Map. +func IsUnique() IsDef { + return ScopedIsUnique().IsUniqueTo("") +} + +// UniqScopeTracker is represents the tracking data for invoking IsUniqueTo. +type UniqScopeTracker map[interface{}]string + +// IsUniqueTo validates that the given value is only ever seen within a single namespace. +func (ust UniqScopeTracker) IsUniqueTo(namespace string) IsDef { + return Is("unique", func(path path, v interface{}) *Results { + for trackerK, trackerNs := range ust { + hasNamespace := len(namespace) > 0 + if reflect.DeepEqual(trackerK, v) && (!hasNamespace || namespace != trackerNs) { + return SimpleResult(path, false, "Value '%v' is repeated", v) + } + } + + ust[v] = namespace + return ValidResult(path) + }) +} + +func ScopedIsUnique() UniqScopeTracker { + return UniqScopeTracker{} +} + // isStrCheck is a helper for IsDefs that must assert that the value is a string first. func isStrCheck(path path, v interface{}) (str string, errorResults *Results) { strV, ok := v.(string) diff --git a/libbeat/common/mapval/is_defs_test.go b/libbeat/common/mapval/is_defs_test.go index a6f0e6dcaaf..f50250595fd 100644 --- a/libbeat/common/mapval/is_defs_test.go +++ b/libbeat/common/mapval/is_defs_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/elastic/beats/libbeat/common" ) @@ -152,3 +153,58 @@ func TestIsNil(t *testing.T) { assertIsDefValid(t, IsNil, nil) assertIsDefInvalid(t, IsNil, "foo") } + +func TestIsUnique(t *testing.T) { + tests := []struct { + name string + validator func() Validator + data common.MapStr + isValid bool + }{ + { + "IsUnique find dupes", + func() Validator { + v := IsUnique() + return MustCompile(Map{"a": v, "b": v}) + }, + common.MapStr{"a": 1, "b": 1}, + false, + }, + { + "IsUnique separate instances don't care about dupes", + func() Validator { return MustCompile(Map{"a": IsUnique(), "b": IsUnique()}) }, + common.MapStr{"a": 1, "b": 1}, + true, + }, + { + "IsUniqueTo duplicates across namespaces fail", + func() Validator { + s := ScopedIsUnique() + return MustCompile(Map{"a": s.IsUniqueTo("test"), "b": s.IsUniqueTo("test2")}) + }, + common.MapStr{"a": 1, "b": 1}, + false, + }, + + { + "IsUniqueTo duplicates within a namespace succeeds", + func() Validator { + s := ScopedIsUnique() + return MustCompile(Map{"a": s.IsUniqueTo("test"), "b": s.IsUniqueTo("test")}) + }, + common.MapStr{"a": 1, "b": 1}, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + if tt.isValid { + Test(t, tt.validator(), tt.data) + } else { + result := tt.validator()(tt.data) + require.False(t, result.Valid) + } + }) + } +} diff --git a/libbeat/testing/mapvaltest/mapvaltest.go b/libbeat/common/mapval/testing.go similarity index 79% rename from libbeat/testing/mapvaltest/mapvaltest.go rename to libbeat/common/mapval/testing.go index 0701d4c61d5..e318b5d5c8a 100644 --- a/libbeat/testing/mapvaltest/mapvaltest.go +++ b/libbeat/common/mapval/testing.go @@ -15,11 +15,7 @@ // specific language governing permissions and limitations // under the License. -package mapvaltest - -// skimatest is a separate package from skima since we don't want to import "testing" -// into skima, since there is a good chance we'll use skima for running user-defined -// tests in heartbeat at runtime. +package mapval import ( "testing" @@ -28,12 +24,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/common/mapval" ) // Test takes the output from a Validator invocation and runs test assertions on the result. // If you are using this library for testing you will probably want to run Test(t, Compile(Map{...}), actual) as a pattern. -func Test(t *testing.T, v mapval.Validator, m common.MapStr) *mapval.Results { +func Test(t *testing.T, v Validator, m common.MapStr) *Results { r := v(m) if !r.Valid { diff --git a/libbeat/testing/mapvaltest/mapvaltest_test.go b/libbeat/testing/mapvaltest/mapvaltest_test.go deleted file mode 100644 index 9f22e28f3dd..00000000000 --- a/libbeat/testing/mapvaltest/mapvaltest_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you under -// the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package mapvaltest - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/elastic/beats/libbeat/common" - "github.com/elastic/beats/libbeat/common/mapval" -) - -func TestTest(t *testing.T) { - // Should pass - Test(t, mapval.MustCompile(mapval.Map{}), common.MapStr{}) - - fakeT := new(testing.T) - Test(fakeT, mapval.MustCompile(mapval.Map{"foo": "bar"}), common.MapStr{}) - - assert.True(t, fakeT.Failed()) -}