190 lines
4.5 KiB
Go
190 lines
4.5 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.
|
||
|
|
||
|
package registrar
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
|
||
|
"github.com/elastic/beats/filebeat/input/file"
|
||
|
)
|
||
|
|
||
|
func TestRegistrarRead(t *testing.T) {
|
||
|
type testCase struct {
|
||
|
input string
|
||
|
expected []file.State
|
||
|
}
|
||
|
|
||
|
zone := time.FixedZone("+0000", 0)
|
||
|
|
||
|
cases := map[string]testCase{
|
||
|
"ok registry with one entry": testCase{
|
||
|
input: `[
|
||
|
{
|
||
|
"type": "log",
|
||
|
"source": "test.log",
|
||
|
"offset": 10,
|
||
|
"timestamp": "2018-07-16T10:45:01+00:00",
|
||
|
"ttl": -1,
|
||
|
"meta": null
|
||
|
}
|
||
|
]`,
|
||
|
expected: []file.State{
|
||
|
{
|
||
|
Type: "log",
|
||
|
Source: "test.log",
|
||
|
Timestamp: time.Date(2018, time.July, 16, 10, 45, 01, 0, zone),
|
||
|
Offset: 10,
|
||
|
TTL: -2, // loader always resets states
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
"load config without meta": testCase{
|
||
|
input: `[
|
||
|
{
|
||
|
"type": "log",
|
||
|
"source": "test.log",
|
||
|
"offset": 10,
|
||
|
"timestamp": "2018-07-16T10:45:01+00:00",
|
||
|
"ttl": -1
|
||
|
}
|
||
|
]`,
|
||
|
expected: []file.State{
|
||
|
{
|
||
|
Type: "log",
|
||
|
Source: "test.log",
|
||
|
Timestamp: time.Date(2018, time.July, 16, 10, 45, 01, 0, zone),
|
||
|
Offset: 10,
|
||
|
TTL: -2, // loader always resets states
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
"load config with empty meta": testCase{
|
||
|
input: `[
|
||
|
{
|
||
|
"type": "log",
|
||
|
"source": "test.log",
|
||
|
"offset": 10,
|
||
|
"timestamp": "2018-07-16T10:45:01+00:00",
|
||
|
"ttl": -1,
|
||
|
"meta": {}
|
||
|
}
|
||
|
]`,
|
||
|
expected: []file.State{
|
||
|
{
|
||
|
Type: "log",
|
||
|
Source: "test.log",
|
||
|
Timestamp: time.Date(2018, time.July, 16, 10, 45, 01, 0, zone),
|
||
|
Offset: 10,
|
||
|
TTL: -2, // loader always resets states
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
|
||
|
"requires merge without meta-data": testCase{
|
||
|
input: `[
|
||
|
{
|
||
|
"type": "log",
|
||
|
"source": "test.log",
|
||
|
"offset": 100,
|
||
|
"timestamp": "2018-07-16T10:45:01+00:00",
|
||
|
"ttl": -1,
|
||
|
"meta": {}
|
||
|
},
|
||
|
{
|
||
|
"type": "log",
|
||
|
"source": "test.log",
|
||
|
"offset": 10,
|
||
|
"timestamp": "2018-07-16T10:45:10+00:00",
|
||
|
"ttl": -1,
|
||
|
"meta": null
|
||
|
}
|
||
|
]`,
|
||
|
expected: []file.State{
|
||
|
{
|
||
|
Type: "log",
|
||
|
Source: "test.log",
|
||
|
Timestamp: time.Date(2018, time.July, 16, 10, 45, 10, 0, zone),
|
||
|
Offset: 100,
|
||
|
TTL: -2, // loader always resets states
|
||
|
Meta: nil,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
matchState := func(t *testing.T, i int, expected, actual file.State) {
|
||
|
check := func(name string, a, b interface{}) {
|
||
|
if !reflect.DeepEqual(a, b) {
|
||
|
t.Errorf("State %v: %v mismatch (expected=%v, actual=%v)", i, name, a, b)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
check("id", expected.ID(), actual.ID())
|
||
|
check("source", expected.Source, actual.Source)
|
||
|
check("offset", expected.Offset, actual.Offset)
|
||
|
check("ttl", expected.TTL, actual.TTL)
|
||
|
check("meta", expected.Meta, actual.Meta)
|
||
|
check("type", expected.Type, actual.Type)
|
||
|
|
||
|
if t1, t2 := expected.Timestamp, actual.Timestamp; !t1.Equal(t2) {
|
||
|
t.Errorf("State %v: timestamp mismatch (expected=%v, actual=%v)", i, t1, t2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for name, test := range cases {
|
||
|
test := test
|
||
|
t.Run(name, func(t *testing.T) {
|
||
|
in := strings.NewReader(test.input)
|
||
|
|
||
|
states, err := readStatesFrom(in)
|
||
|
if !assert.NoError(t, err) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
actual := sortedStates(states)
|
||
|
expected := sortedStates(test.expected)
|
||
|
if len(actual) != len(expected) {
|
||
|
t.Errorf("expected %v state, but registrar did load %v states",
|
||
|
len(expected), len(actual))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
for i := range expected {
|
||
|
matchState(t, i, expected[i], actual[i])
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func sortedStates(states []file.State) []file.State {
|
||
|
tmp := make([]file.State, len(states))
|
||
|
copy(tmp, states)
|
||
|
sort.Slice(tmp, func(i, j int) bool {
|
||
|
return tmp[i].ID() < tmp[j].ID()
|
||
|
})
|
||
|
return tmp
|
||
|
}
|