827 lines
14 KiB
Go
827 lines
14 KiB
Go
|
// 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.
|
||
|
|
||
|
// +build !integration
|
||
|
|
||
|
package common
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"go.uber.org/zap/zapcore"
|
||
|
|
||
|
"github.com/elastic/beats/libbeat/logp"
|
||
|
)
|
||
|
|
||
|
func TestMapStrUpdate(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
a := MapStr{
|
||
|
"a": 1,
|
||
|
"b": 2,
|
||
|
}
|
||
|
b := MapStr{
|
||
|
"b": 3,
|
||
|
"c": 4,
|
||
|
}
|
||
|
|
||
|
a.Update(b)
|
||
|
|
||
|
assert.Equal(a, MapStr{"a": 1, "b": 3, "c": 4})
|
||
|
}
|
||
|
|
||
|
func TestMapStrDeepUpdate(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
a, b, expected MapStr
|
||
|
}{
|
||
|
{
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"b": 2},
|
||
|
MapStr{"a": 1, "b": 2},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"a": 2},
|
||
|
MapStr{"a": 2},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
MapStr{"a": MapStr{"c": 2}},
|
||
|
MapStr{"a": MapStr{"b": 1, "c": 2}},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"a": 1},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a.b": 1},
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"a": 1, "a.b": 1},
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": 1},
|
||
|
MapStr{"a.b": 1},
|
||
|
MapStr{"a": 1, "a.b": 1},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for i, test := range tests {
|
||
|
a, b, expected := test.a, test.b, test.expected
|
||
|
name := fmt.Sprintf("%v: %v + %v = %v", i, a, b, expected)
|
||
|
|
||
|
t.Run(name, func(t *testing.T) {
|
||
|
a.DeepUpdate(b)
|
||
|
assert.Equal(t, expected, a)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestMapStrUnion(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
a := MapStr{
|
||
|
"a": 1,
|
||
|
"b": 2,
|
||
|
}
|
||
|
b := MapStr{
|
||
|
"b": 3,
|
||
|
"c": 4,
|
||
|
}
|
||
|
|
||
|
c := MapStrUnion(a, b)
|
||
|
|
||
|
assert.Equal(c, MapStr{"a": 1, "b": 3, "c": 4})
|
||
|
}
|
||
|
|
||
|
func TestMapStrCopyFieldsTo(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
m := MapStr{
|
||
|
"a": MapStr{
|
||
|
"a1": 2,
|
||
|
"a2": 3,
|
||
|
},
|
||
|
"b": 2,
|
||
|
"c": MapStr{
|
||
|
"c1": 1,
|
||
|
"c2": 2,
|
||
|
"c3": MapStr{
|
||
|
"c31": 1,
|
||
|
"c32": 2,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
c := MapStr{}
|
||
|
|
||
|
err := m.CopyFieldsTo(c, "dd")
|
||
|
assert.Error(err)
|
||
|
assert.Equal(MapStr{}, c)
|
||
|
|
||
|
err = m.CopyFieldsTo(c, "a")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"a": MapStr{"a1": 2, "a2": 3}}, c)
|
||
|
|
||
|
err = m.CopyFieldsTo(c, "c.c1")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"a": MapStr{"a1": 2, "a2": 3}, "c": MapStr{"c1": 1}}, c)
|
||
|
|
||
|
err = m.CopyFieldsTo(c, "b")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"a": MapStr{"a1": 2, "a2": 3}, "c": MapStr{"c1": 1}, "b": 2}, c)
|
||
|
|
||
|
err = m.CopyFieldsTo(c, "c.c3.c32")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"a": MapStr{"a1": 2, "a2": 3}, "c": MapStr{"c1": 1, "c3": MapStr{"c32": 2}}, "b": 2}, c)
|
||
|
}
|
||
|
|
||
|
func TestMapStrDelete(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
m := MapStr{
|
||
|
"c": MapStr{
|
||
|
"c1": 1,
|
||
|
"c2": 2,
|
||
|
"c3": MapStr{
|
||
|
"c31": 1,
|
||
|
"c32": 2,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
err := m.Delete("c.c2")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"c": MapStr{"c1": 1, "c3": MapStr{"c31": 1, "c32": 2}}}, m)
|
||
|
|
||
|
err = m.Delete("c.c2.c21")
|
||
|
assert.NotEqual(nil, err)
|
||
|
assert.Equal(MapStr{"c": MapStr{"c1": 1, "c3": MapStr{"c31": 1, "c32": 2}}}, m)
|
||
|
|
||
|
err = m.Delete("c.c3.c31")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{"c": MapStr{"c1": 1, "c3": MapStr{"c32": 2}}}, m)
|
||
|
|
||
|
err = m.Delete("c")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(MapStr{}, m)
|
||
|
}
|
||
|
|
||
|
func TestHasKey(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
m := MapStr{
|
||
|
"c": MapStr{
|
||
|
"c1": 1,
|
||
|
"c2": 2,
|
||
|
"c3": MapStr{
|
||
|
"c31": 1,
|
||
|
"c32": 2,
|
||
|
},
|
||
|
"c4.f": 19,
|
||
|
},
|
||
|
"d.f": 1,
|
||
|
}
|
||
|
|
||
|
hasKey, err := m.HasKey("c.c2")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(true, hasKey)
|
||
|
|
||
|
hasKey, err = m.HasKey("c.c4")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(false, hasKey)
|
||
|
|
||
|
hasKey, err = m.HasKey("c.c3.c32")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(true, hasKey)
|
||
|
|
||
|
hasKey, err = m.HasKey("dd")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(false, hasKey)
|
||
|
|
||
|
hasKey, err = m.HasKey("d.f")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(true, hasKey)
|
||
|
|
||
|
hasKey, err = m.HasKey("c.c4.f")
|
||
|
assert.Equal(nil, err)
|
||
|
assert.Equal(true, hasKey)
|
||
|
}
|
||
|
|
||
|
func TestMapStrPut(t *testing.T) {
|
||
|
m := MapStr{
|
||
|
"subMap": MapStr{
|
||
|
"a": 1,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
// Add new value to the top-level.
|
||
|
v, err := m.Put("a", "ok")
|
||
|
assert.NoError(t, err)
|
||
|
assert.Nil(t, v)
|
||
|
assert.Equal(t, MapStr{"a": "ok", "subMap": MapStr{"a": 1}}, m)
|
||
|
|
||
|
// Add new value to subMap.
|
||
|
v, err = m.Put("subMap.b", 2)
|
||
|
assert.NoError(t, err)
|
||
|
assert.Nil(t, v)
|
||
|
assert.Equal(t, MapStr{"a": "ok", "subMap": MapStr{"a": 1, "b": 2}}, m)
|
||
|
|
||
|
// Overwrite a value in subMap.
|
||
|
v, err = m.Put("subMap.a", 2)
|
||
|
assert.NoError(t, err)
|
||
|
assert.Equal(t, 1, v)
|
||
|
assert.Equal(t, MapStr{"a": "ok", "subMap": MapStr{"a": 2, "b": 2}}, m)
|
||
|
|
||
|
// Add value to map that does not exist.
|
||
|
m = MapStr{}
|
||
|
v, err = m.Put("subMap.newMap.a", 1)
|
||
|
assert.NoError(t, err)
|
||
|
assert.Nil(t, v)
|
||
|
assert.Equal(t, MapStr{"subMap": MapStr{"newMap": MapStr{"a": 1}}}, m)
|
||
|
}
|
||
|
|
||
|
func TestMapStrGetValue(t *testing.T) {
|
||
|
|
||
|
tests := []struct {
|
||
|
input MapStr
|
||
|
key string
|
||
|
output interface{}
|
||
|
error bool
|
||
|
}{
|
||
|
{
|
||
|
MapStr{"a": 1},
|
||
|
"a",
|
||
|
1,
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
"a",
|
||
|
MapStr{"b": 1},
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b": 1}},
|
||
|
"a.b",
|
||
|
1,
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b.c": 1}},
|
||
|
"a",
|
||
|
MapStr{"b.c": 1},
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b.c": 1}},
|
||
|
"a.b",
|
||
|
nil,
|
||
|
true,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a.b": MapStr{"c": 1}},
|
||
|
"a.b",
|
||
|
MapStr{"c": 1},
|
||
|
false,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a.b": MapStr{"c": 1}},
|
||
|
"a.b.c",
|
||
|
nil,
|
||
|
true,
|
||
|
},
|
||
|
{
|
||
|
MapStr{"a": MapStr{"b.c": 1}},
|
||
|
"a.b.c",
|
||
|
1,
|
||
|
false,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
v, err := test.input.GetValue(test.key)
|
||
|
if test.error {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
}
|
||
|
assert.Equal(t, test.output, v)
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestClone(t *testing.T) {
|
||
|
assert := assert.New(t)
|
||
|
|
||
|
m := MapStr{
|
||
|
"c1": 1,
|
||
|
"c2": 2,
|
||
|
"c3": MapStr{
|
||
|
"c31": 1,
|
||
|
"c32": 2,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
c := m.Clone()
|
||
|
assert.Equal(MapStr{"c31": 1, "c32": 2}, c["c3"])
|
||
|
}
|
||
|
|
||
|
func TestString(t *testing.T) {
|
||
|
type io struct {
|
||
|
Input MapStr
|
||
|
Output string
|
||
|
}
|
||
|
tests := []io{
|
||
|
{
|
||
|
Input: MapStr{
|
||
|
"a": "b",
|
||
|
},
|
||
|
Output: `{"a":"b"}`,
|
||
|
},
|
||
|
{
|
||
|
Input: MapStr{
|
||
|
"a": []int{1, 2, 3},
|
||
|
},
|
||
|
Output: `{"a":[1,2,3]}`,
|
||
|
},
|
||
|
}
|
||
|
for _, test := range tests {
|
||
|
assert.Equal(t, test.Output, test.Input.String())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Smoke test. The method has no observable outputs so this
|
||
|
// is only verifying there are no panics.
|
||
|
func TestStringToPrint(t *testing.T) {
|
||
|
m := MapStr{}
|
||
|
|
||
|
assert.Equal(t, "{}", m.StringToPrint())
|
||
|
assert.Equal(t, true, len(m.StringToPrint()) > 0)
|
||
|
}
|
||
|
|
||
|
func TestMergeFields(t *testing.T) {
|
||
|
type io struct {
|
||
|
UnderRoot bool
|
||
|
Event MapStr
|
||
|
Fields MapStr
|
||
|
Output MapStr
|
||
|
Err string
|
||
|
}
|
||
|
tests := []io{
|
||
|
// underRoot = true, merges
|
||
|
{
|
||
|
UnderRoot: true,
|
||
|
Event: MapStr{
|
||
|
"a": "1",
|
||
|
},
|
||
|
Fields: MapStr{
|
||
|
"b": 2,
|
||
|
},
|
||
|
Output: MapStr{
|
||
|
"a": "1",
|
||
|
"b": 2,
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// underRoot = true, overwrites existing
|
||
|
{
|
||
|
UnderRoot: true,
|
||
|
Event: MapStr{
|
||
|
"a": "1",
|
||
|
},
|
||
|
Fields: MapStr{
|
||
|
"a": 2,
|
||
|
},
|
||
|
Output: MapStr{
|
||
|
"a": 2,
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// underRoot = false, adds new 'fields' when it doesn't exist
|
||
|
{
|
||
|
UnderRoot: false,
|
||
|
Event: MapStr{
|
||
|
"a": "1",
|
||
|
},
|
||
|
Fields: MapStr{
|
||
|
"a": 2,
|
||
|
},
|
||
|
Output: MapStr{
|
||
|
"a": "1",
|
||
|
"fields": MapStr{
|
||
|
"a": 2,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// underRoot = false, merge with existing 'fields' and overwrites existing keys
|
||
|
{
|
||
|
UnderRoot: false,
|
||
|
Event: MapStr{
|
||
|
"fields": MapStr{
|
||
|
"a": "1",
|
||
|
"b": 2,
|
||
|
},
|
||
|
},
|
||
|
Fields: MapStr{
|
||
|
"a": 3,
|
||
|
"c": 4,
|
||
|
},
|
||
|
Output: MapStr{
|
||
|
"fields": MapStr{
|
||
|
"a": 3,
|
||
|
"b": 2,
|
||
|
"c": 4,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
// underRoot = false, error when 'fields' is wrong type
|
||
|
{
|
||
|
UnderRoot: false,
|
||
|
Event: MapStr{
|
||
|
"fields": "not a MapStr",
|
||
|
},
|
||
|
Fields: MapStr{
|
||
|
"a": 3,
|
||
|
},
|
||
|
Output: MapStr{
|
||
|
"fields": "not a MapStr",
|
||
|
},
|
||
|
Err: "expected map",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
err := MergeFields(test.Event, test.Fields, test.UnderRoot)
|
||
|
assert.Equal(t, test.Output, test.Event)
|
||
|
if test.Err != "" {
|
||
|
assert.Contains(t, err.Error(), test.Err)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAddTag(t *testing.T) {
|
||
|
type io struct {
|
||
|
Event MapStr
|
||
|
Tags []string
|
||
|
Output MapStr
|
||
|
Err string
|
||
|
}
|
||
|
tests := []io{
|
||
|
// No existing tags, creates new tag array
|
||
|
{
|
||
|
Event: MapStr{},
|
||
|
Tags: []string{"json"},
|
||
|
Output: MapStr{
|
||
|
"tags": []string{"json"},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags is a []string, appends
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"tags": []string{"json"},
|
||
|
},
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"tags": []string{"json", "docker"},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags is a []interface{}, appends
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"tags": []interface{}{"json"},
|
||
|
},
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"tags": []interface{}{"json", "docker"},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags is not a []string or []interface{}
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"tags": "not a slice",
|
||
|
},
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"tags": "not a slice",
|
||
|
},
|
||
|
Err: "expected string array",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
err := AddTags(test.Event, test.Tags)
|
||
|
assert.Equal(t, test.Output, test.Event)
|
||
|
if test.Err != "" {
|
||
|
assert.Contains(t, err.Error(), test.Err)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAddTagsWithKey(t *testing.T) {
|
||
|
type io struct {
|
||
|
Event MapStr
|
||
|
Key string
|
||
|
Tags []string
|
||
|
Output MapStr
|
||
|
Err string
|
||
|
}
|
||
|
tests := []io{
|
||
|
// No existing tags, creates new tag array
|
||
|
{
|
||
|
Event: MapStr{},
|
||
|
Key: "tags",
|
||
|
Tags: []string{"json"},
|
||
|
Output: MapStr{
|
||
|
"tags": []string{"json"},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags is a []string, appends
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"tags": []string{"json"},
|
||
|
},
|
||
|
Key: "tags",
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"tags": []string{"json", "docker"},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags are in submap and is a []interface{}, appends
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"log": MapStr{
|
||
|
"flags": []interface{}{"json"},
|
||
|
},
|
||
|
},
|
||
|
Key: "log.flags",
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"log": MapStr{
|
||
|
"flags": []interface{}{"json", "docker"},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
// Existing tags are in a submap and is not a []string or []interface{}
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"log": MapStr{
|
||
|
"flags": "not a slice",
|
||
|
},
|
||
|
},
|
||
|
Key: "log.flags",
|
||
|
Tags: []string{"docker"},
|
||
|
Output: MapStr{
|
||
|
"log": MapStr{
|
||
|
"flags": "not a slice",
|
||
|
},
|
||
|
},
|
||
|
Err: "expected string array",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
err := AddTagsWithKey(test.Event, test.Key, test.Tags)
|
||
|
assert.Equal(t, test.Output, test.Event)
|
||
|
if test.Err != "" {
|
||
|
assert.Contains(t, err.Error(), test.Err)
|
||
|
} else {
|
||
|
assert.NoError(t, err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFlatten(t *testing.T) {
|
||
|
type data struct {
|
||
|
Event MapStr
|
||
|
Expected MapStr
|
||
|
}
|
||
|
tests := []data{
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"hello": MapStr{
|
||
|
"world": 15,
|
||
|
},
|
||
|
},
|
||
|
Expected: MapStr{
|
||
|
"hello.world": 15,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"test": 15,
|
||
|
},
|
||
|
Expected: MapStr{
|
||
|
"test": 15,
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
Event: MapStr{
|
||
|
"test": 15,
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
"elastic": MapStr{
|
||
|
"for": "search",
|
||
|
},
|
||
|
},
|
||
|
Expected: MapStr{
|
||
|
"test": 15,
|
||
|
"hello.world.ok": "test",
|
||
|
"elastic.for": "search",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
assert.Equal(t, test.Expected, test.Event.Flatten())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkMapStrFlatten(b *testing.B) {
|
||
|
m := MapStr{
|
||
|
"test": 15,
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
"elastic": MapStr{
|
||
|
"for": "search",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
_ = m.Flatten()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Ensure the MapStr is marshaled in logs the same way it is by json.Marshal.
|
||
|
func TestMapStrJSONLog(t *testing.T) {
|
||
|
logp.DevelopmentSetup(logp.ToObserverOutput())
|
||
|
|
||
|
m := MapStr{
|
||
|
"test": 15,
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
"elastic": MapStr{
|
||
|
"for": "search",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
data, err := json.Marshal(MapStr{"m": m})
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
expectedJSON := string(data)
|
||
|
|
||
|
logp.NewLogger("test").Infow("msg", "m", m)
|
||
|
logs := logp.ObserverLogs().TakeAll()
|
||
|
if assert.Len(t, logs, 1) {
|
||
|
log := logs[0]
|
||
|
|
||
|
// Encode like zap does.
|
||
|
e := zapcore.NewJSONEncoder(zapcore.EncoderConfig{})
|
||
|
buf, err := e.EncodeEntry(log.Entry, log.Context)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Zap adds a newline to end the JSON object.
|
||
|
actualJSON := strings.TrimSpace(buf.String())
|
||
|
|
||
|
assert.Equal(t, string(expectedJSON), actualJSON)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkMapStrLogging(b *testing.B) {
|
||
|
logp.DevelopmentSetup(logp.ToDiscardOutput())
|
||
|
logger := logp.NewLogger("benchtest")
|
||
|
|
||
|
m := MapStr{
|
||
|
"test": 15,
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
"elastic": MapStr{
|
||
|
"for": "search",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
logger.Infow("test", "mapstr", m)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func BenchmarkWalkMap(b *testing.B) {
|
||
|
|
||
|
globalM := MapStr{
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
b.Run("Get", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
globalM.GetValue("test.world.ok")
|
||
|
}
|
||
|
})
|
||
|
|
||
|
b.Run("Put", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
m := MapStr{
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
m.Put("hello.world.new", 17)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
b.Run("PutMissing", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
m := MapStr{}
|
||
|
|
||
|
m.Put("a.b.c", 17)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
b.Run("HasKey", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
globalM.HasKey("hello.world.ok")
|
||
|
globalM.HasKey("hello.world.no_ok")
|
||
|
}
|
||
|
})
|
||
|
|
||
|
b.Run("HasKeyFirst", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
globalM.HasKey("hello")
|
||
|
}
|
||
|
})
|
||
|
|
||
|
b.Run("Delete", func(b *testing.B) {
|
||
|
b.ResetTimer()
|
||
|
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
m := MapStr{
|
||
|
"hello": MapStr{
|
||
|
"world": MapStr{
|
||
|
"ok": "test",
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
m.Put("hello.world.test", 17)
|
||
|
}
|
||
|
})
|
||
|
}
|