forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cherry-pick elastic#19227 to 7.x: Add statestore test helpers and uni…
…t tests (elastic#19689) Add statestore test helpers and unit tests This change introduces the libbeat/statestore/storetest package and unit tests to the statestore frontend itself. The storetest package provides helpers for writing tests. For example does it emulate a key value store in memory by storing all k/v-pairs in a map[string]interface{}, that can optionally provided by users. The internal storecompliance test-suite is used to validate the storetest package to be fully compatible with the statestore requirements. The addition of the statestore package is split up into multiple changeset to ease review. The final version of the package can be found [here](https://github.com/urso/beats/tree/fb-input-v2-combined/libbeat/statestore). Once finalized, the libbeat/statestore package contains: - The statestore frontend and interface for use within Beats - Interfaces for the store backend - A common set of tests store backends need to support - a storetest package for testing new features that require a store. The testing helpers use map[string]interface{} that can be initialized or queried after the test run for validation purposes. - The default memlog backend + tests This change introduces the second last item to libbeat: test helpers and additional unit tests. (cherry picked from commit 372c3ae)
- Loading branch information
Steffen Siering
authored
Jul 7, 2020
1 parent
db27fe0
commit d2c02aa
Showing
5 changed files
with
695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// 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 statestore | ||
|
||
import ( | ||
"github.com/stretchr/testify/mock" | ||
|
||
"github.com/elastic/beats/v7/libbeat/statestore/backend" | ||
) | ||
|
||
type mockRegistry struct { | ||
mock.Mock | ||
} | ||
|
||
type mockStore struct { | ||
mock.Mock | ||
} | ||
|
||
func newMockRegistry() *mockRegistry { return &mockRegistry{} } | ||
|
||
func (m *mockRegistry) OnAccess(name string) *mock.Call { return m.On("Access", name) } | ||
func (m *mockRegistry) Access(name string) (backend.Store, error) { | ||
args := m.Called(name) | ||
|
||
var store backend.Store | ||
if ifc := args.Get(0); ifc != nil { | ||
store = ifc.(backend.Store) | ||
} | ||
|
||
return store, args.Error(1) | ||
} | ||
|
||
func (m *mockRegistry) OnClose() *mock.Call { return m.On("Close") } | ||
func (m *mockRegistry) Close() error { | ||
args := m.Called() | ||
return args.Error(0) | ||
} | ||
|
||
func newMockStore() *mockStore { return &mockStore{} } | ||
|
||
func (m *mockStore) OnClose() *mock.Call { return m.On("Close") } | ||
func (m *mockStore) Close() error { | ||
args := m.Called() | ||
return args.Error(0) | ||
} | ||
|
||
func (m *mockStore) OnHas(key string) *mock.Call { return m.On("Has", key) } | ||
func (m *mockStore) Has(key string) (bool, error) { | ||
args := m.Called(key) | ||
return args.Bool(0), args.Error(1) | ||
} | ||
|
||
func (m *mockStore) OnGet(key string) *mock.Call { return m.On("Get", key) } | ||
func (m *mockStore) Get(key string, into interface{}) error { | ||
args := m.Called(key) | ||
return args.Error(0) | ||
} | ||
|
||
func (m *mockStore) OnRemove(key string) *mock.Call { return m.On("Remove", key) } | ||
func (m *mockStore) Remove(key string) error { | ||
args := m.Called(key) | ||
return args.Error(0) | ||
} | ||
|
||
func (m *mockStore) OnSet(key string) *mock.Call { return m.On("Set", key) } | ||
func (m *mockStore) Set(key string, from interface{}) error { | ||
args := m.Called(key) | ||
return args.Error(0) | ||
} | ||
|
||
func (m *mockStore) Each(fn func(string, backend.ValueDecoder) (bool, error)) error { | ||
args := m.Called(fn) | ||
return args.Error(0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// 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 statestore | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAccessStore(t *testing.T) { | ||
t.Run("single access", func(t *testing.T) { | ||
mr := newMockRegistry() | ||
ms := newMockStore() | ||
mr.OnClose().Once().Return(nil) | ||
mr.OnAccess("test").Once().Return(ms, nil) | ||
ms.OnClose().Once().Return(nil) | ||
|
||
reg := NewRegistry(mr) | ||
store, _ := reg.Get("test") | ||
assert.NoError(t, store.Close()) | ||
assert.NoError(t, reg.Close()) | ||
|
||
mr.AssertExpectations(t) | ||
ms.AssertExpectations(t) | ||
}) | ||
|
||
t.Run("shared store instance", func(t *testing.T) { | ||
mr := newMockRegistry() | ||
ms := newMockStore() | ||
mr.OnClose().Once().Return(nil) | ||
|
||
// test instance sharing. Store must be opened and closed only once | ||
mr.OnAccess("test").Once().Return(ms, nil) | ||
ms.OnClose().Once().Return(nil) | ||
|
||
reg := NewRegistry(mr) | ||
s1, _ := reg.Get("test") | ||
s2, _ := reg.Get("test") | ||
assert.NoError(t, s1.Close()) | ||
assert.NoError(t, s2.Close()) | ||
assert.NoError(t, reg.Close()) | ||
|
||
mr.AssertExpectations(t) | ||
ms.AssertExpectations(t) | ||
}) | ||
|
||
t.Run("close non-shared store needs open", func(t *testing.T) { | ||
mr := newMockRegistry() | ||
ms := newMockStore() | ||
mr.OnClose().Once().Return(nil) | ||
|
||
// test instance sharing. Store must be opened and closed only once | ||
mr.OnAccess("test").Twice().Return(ms, nil) | ||
ms.OnClose().Twice().Return(nil) | ||
|
||
reg := NewRegistry(mr) | ||
|
||
store, err := reg.Get("test") | ||
assert.NoError(t, err) | ||
assert.NoError(t, store.Close()) | ||
|
||
store, err = reg.Get("test") | ||
assert.NoError(t, err) | ||
assert.NoError(t, store.Close()) | ||
|
||
assert.NoError(t, reg.Close()) | ||
|
||
mr.AssertExpectations(t) | ||
ms.AssertExpectations(t) | ||
}) | ||
|
||
t.Run("separate stores are not shared", func(t *testing.T) { | ||
mr := newMockRegistry() | ||
mr.OnClose().Once().Return(nil) | ||
|
||
ms1 := newMockStore() | ||
ms1.OnClose().Once().Return(nil) | ||
mr.OnAccess("s1").Once().Return(ms1, nil) | ||
|
||
ms2 := newMockStore() | ||
ms2.OnClose().Once().Return(nil) | ||
mr.OnAccess("s2").Once().Return(ms2, nil) | ||
|
||
reg := NewRegistry(mr) | ||
s1, err := reg.Get("s1") | ||
assert.NoError(t, err) | ||
s2, err := reg.Get("s2") | ||
assert.NoError(t, err) | ||
assert.NoError(t, s1.Close()) | ||
assert.NoError(t, s2.Close()) | ||
assert.NoError(t, reg.Close()) | ||
|
||
mr.AssertExpectations(t) | ||
ms1.AssertExpectations(t) | ||
ms2.AssertExpectations(t) | ||
}) | ||
} |
Oops, something went wrong.