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