Merge pull request #173 from v2tec/filters
Filters refactoring and always exclude disabled containerspull/174/head
commit
88a7a084a9
@ -0,0 +1,75 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
// A Filter is a prototype for a function that can be used to filter the
|
||||||
|
// results from a call to the ListContainers() method on the Client.
|
||||||
|
type Filter func(FilterableContainer) bool
|
||||||
|
|
||||||
|
// A FilterableContainer is the interface which is used to filter
|
||||||
|
// containers.
|
||||||
|
type FilterableContainer interface {
|
||||||
|
Name() string
|
||||||
|
IsWatchtower() bool
|
||||||
|
Enabled() (bool, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchtowerContainersFilter filters only watchtower containers
|
||||||
|
func WatchtowerContainersFilter(c FilterableContainer) bool { return c.IsWatchtower() }
|
||||||
|
|
||||||
|
// Filter no containers and returns all
|
||||||
|
func noFilter(FilterableContainer) bool { return true }
|
||||||
|
|
||||||
|
// Filters containers which don't have a specified name
|
||||||
|
func filterByNames(names []string, baseFilter Filter) Filter {
|
||||||
|
if len(names) == 0 {
|
||||||
|
return baseFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(c FilterableContainer) bool {
|
||||||
|
for _, name := range names {
|
||||||
|
if (name == c.Name()) || (name == c.Name()[1:]) {
|
||||||
|
return baseFilter(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filters out containers that don't have the 'enableLabel'
|
||||||
|
func filterByEnableLabel(baseFilter Filter) Filter {
|
||||||
|
return func(c FilterableContainer) bool {
|
||||||
|
// If label filtering is enabled, containers should only be considered
|
||||||
|
// if the label is specifically set.
|
||||||
|
_, ok := c.Enabled()
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseFilter(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filters out containers that have a 'enableLabel' and is set to disable.
|
||||||
|
func filterByDisabledLabel(baseFilter Filter) Filter {
|
||||||
|
return func(c FilterableContainer) bool {
|
||||||
|
enabledLabel, ok := c.Enabled()
|
||||||
|
if ok && !enabledLabel {
|
||||||
|
// If the label has been set and it demands a disable
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseFilter(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFilter creates the needed filter of containers
|
||||||
|
func BuildFilter(names []string, enableLabel bool) Filter {
|
||||||
|
filter := noFilter
|
||||||
|
filter = filterByNames(names, filter)
|
||||||
|
if enableLabel {
|
||||||
|
// If label filtering is enabled, containers should only be considered
|
||||||
|
// if the label is specifically set.
|
||||||
|
filter = filterByEnableLabel(filter)
|
||||||
|
}
|
||||||
|
filter = filterByDisabledLabel(filter)
|
||||||
|
return filter
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/v2tec/watchtower/container/mocks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWatchtowerContainersFilter(t *testing.T) {
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
|
||||||
|
container.On("IsWatchtower").Return(true)
|
||||||
|
|
||||||
|
assert.True(t, WatchtowerContainersFilter(container))
|
||||||
|
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoFilter(t *testing.T) {
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
|
||||||
|
assert.True(t, noFilter(container))
|
||||||
|
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterByNames(t *testing.T) {
|
||||||
|
var names []string
|
||||||
|
|
||||||
|
filter := filterByNames(names, nil)
|
||||||
|
assert.Nil(t, filter)
|
||||||
|
|
||||||
|
names = append(names, "test")
|
||||||
|
|
||||||
|
filter = filterByNames(names, noFilter)
|
||||||
|
assert.NotNil(t, filter)
|
||||||
|
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("test")
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("NoTest")
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterByEnableLabel(t *testing.T) {
|
||||||
|
filter := filterByEnableLabel(noFilter)
|
||||||
|
assert.NotNil(t, filter)
|
||||||
|
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(true, true)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, true)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, false)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterByDisabledLabel(t *testing.T) {
|
||||||
|
filter := filterByDisabledLabel(noFilter)
|
||||||
|
assert.NotNil(t, filter)
|
||||||
|
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(true, true)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, true)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, false)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildFilter(t *testing.T) {
|
||||||
|
var names []string
|
||||||
|
names = append(names, "test")
|
||||||
|
|
||||||
|
filter := BuildFilter(names, false)
|
||||||
|
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("Invalid")
|
||||||
|
container.On("Enabled").Return(false, false)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("test")
|
||||||
|
container.On("Enabled").Return(false, false)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("Invalid")
|
||||||
|
container.On("Enabled").Return(true, true)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("test")
|
||||||
|
container.On("Enabled").Return(true, true)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, true)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildFilterEnableLabel(t *testing.T) {
|
||||||
|
var names []string
|
||||||
|
names = append(names, "test")
|
||||||
|
|
||||||
|
filter := BuildFilter(names, true)
|
||||||
|
|
||||||
|
container := new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, false)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("Invalid")
|
||||||
|
container.On("Enabled").Twice().Return(true, true)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Name").Return("test")
|
||||||
|
container.On("Enabled").Twice().Return(true, true)
|
||||||
|
assert.True(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
|
||||||
|
container = new(mocks.FilterableContainer)
|
||||||
|
container.On("Enabled").Return(false, true)
|
||||||
|
assert.False(t, filter(container))
|
||||||
|
container.AssertExpectations(t)
|
||||||
|
}
|
@ -1,42 +0,0 @@
|
|||||||
package mockclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/v2tec/watchtower/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockClient struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) ListContainers(cf container.Filter) ([]container.Container, error) {
|
|
||||||
args := m.Called(cf)
|
|
||||||
return args.Get(0).([]container.Container), args.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) StopContainer(c container.Container, timeout time.Duration) error {
|
|
||||||
args := m.Called(c, timeout)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) StartContainer(c container.Container) error {
|
|
||||||
args := m.Called(c)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) RenameContainer(c container.Container, name string) error {
|
|
||||||
args := m.Called(c, name)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) IsContainerStale(c container.Container) (bool, error) {
|
|
||||||
args := m.Called(c)
|
|
||||||
return args.Bool(0), args.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MockClient) RemoveImage(c container.Container) error {
|
|
||||||
args := m.Called(c)
|
|
||||||
return args.Error(0)
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package mockclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/v2tec/watchtower/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMockInterface(t *testing.T) {
|
|
||||||
iface := reflect.TypeOf((*container.Client)(nil)).Elem()
|
|
||||||
mock := &MockClient{}
|
|
||||||
|
|
||||||
if !reflect.TypeOf(mock).Implements(iface) {
|
|
||||||
t.Fatalf("Mock does not implement the Client interface")
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,57 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
// FilterableContainer is an autogenerated mock type for the FilterableContainer type
|
||||||
|
type FilterableContainer struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled provides a mock function with given fields:
|
||||||
|
func (_m *FilterableContainer) Enabled() (bool, bool) {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 bool
|
||||||
|
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 bool
|
||||||
|
if rf, ok := ret.Get(1).(func() bool); ok {
|
||||||
|
r1 = rf()
|
||||||
|
} else {
|
||||||
|
r1 = ret.Get(1).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWatchtower provides a mock function with given fields:
|
||||||
|
func (_m *FilterableContainer) IsWatchtower() bool {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 bool
|
||||||
|
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name provides a mock function with given fields:
|
||||||
|
func (_m *FilterableContainer) Name() string {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 string
|
||||||
|
if rf, ok := ret.Get(0).(func() string); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
Loading…
Reference in New Issue