Merge pull request #4943 from vmarmol/image-manager

Implementing ImageManager to take over image lifecycle.
This commit is contained in:
Dawn Chen 2015-03-06 11:09:38 -08:00
commit 3835e0e6e6
8 changed files with 1613 additions and 1 deletions

6
Godeps/Godeps.json generated
View File

@ -1,6 +1,6 @@
{
"ImportPath": "github.com/GoogleCloudPlatform/kubernetes",
"GoVersion": "go1.4",
"GoVersion": "go1.4.1",
"Packages": [
"./..."
],
@ -271,6 +271,10 @@
"ImportPath": "github.com/stretchr/testify/mock",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
},
{
"ImportPath": "github.com/stretchr/testify/require",
"Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
},
{
"ImportPath": "github.com/vaughan0/go-ini",
"Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"

View File

@ -0,0 +1,77 @@
// Alternative testing tools which stop test execution if test failed.
//
// Example Usage
//
// The following is a complete example using require in a standard test function:
// import (
// "testing"
// "github.com/stretchr/testify/require"
// )
//
// func TestSomething(t *testing.T) {
//
// var a string = "Hello"
// var b string = "Hello"
//
// require.Equal(t, a, b, "The two words should be the same.")
//
// }
//
// Assertions
//
// The `require` package have same global functions as in the `assert` package,
// but instead of returning a boolean result they call `t.FailNow()`.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
// require.Equal(t, expected, actual [, message [, format-args])
//
// require.NotEqual(t, notExpected, actual [, message [, format-args]])
//
// require.True(t, actualBool [, message [, format-args]])
//
// require.False(t, actualBool [, message [, format-args]])
//
// require.Nil(t, actualObject [, message [, format-args]])
//
// require.NotNil(t, actualObject [, message [, format-args]])
//
// require.Empty(t, actualObject [, message [, format-args]])
//
// require.NotEmpty(t, actualObject [, message [, format-args]])
//
// require.Error(t, errorObject [, message [, format-args]])
//
// require.NoError(t, errorObject [, message [, format-args]])
//
// require.EqualError(t, theError, errString [, message [, format-args]])
//
// require.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
// require.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
// require.Contains(t, string, substring [, message [, format-args]])
//
// require.NotContains(t, string, substring [, message [, format-args]])
//
// require.Panics(t, func(){
//
// // call code that should panic
//
// } [, message [, format-args]])
//
// require.NotPanics(t, func(){
//
// // call code that should not panic
//
// } [, message [, format-args]])
//
// require.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
// require.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
// require.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
package require

View File

@ -0,0 +1,211 @@
package require
import (
"time"
"github.com/stretchr/testify/assert"
)
type Assertions struct {
t TestingT
}
func New(t TestingT) *Assertions {
return &Assertions{
t: t,
}
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
FailNow(a.t, failureMessage, msgAndArgs...)
}
// Implements asserts that an object is implemented by the specified interface.
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
Implements(a.t, interfaceObject, object, msgAndArgs...)
}
// IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
IsType(a.t, expectedType, object, msgAndArgs...)
}
// Equal asserts that two objects are equal.
//
// require.Equal(123, 123, "123 and 123 should be equal")
func (a *Assertions) Equal(expected, actual interface{}, msgAndArgs ...interface{}) {
Equal(a.t, expected, actual, msgAndArgs...)
}
// Exactly asserts that two objects are equal is value and type.
//
// require.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
func (a *Assertions) Exactly(expected, actual interface{}, msgAndArgs ...interface{}) {
Exactly(a.t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// require.NotNil(err, "err should be something")
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
NotNil(a.t, object, msgAndArgs...)
}
// Nil asserts that the specified object is nil.
//
// require.Nil(err, "err should be nothing")
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
Nil(a.t, object, msgAndArgs...)
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or a
// slice with len == 0.
//
// require.Empty(obj)
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
Empty(a.t, object, msgAndArgs...)
}
// Empty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or a
// slice with len == 0.
//
// if require.NotEmpty(obj) {
// require.Equal("two", obj[1])
// }
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
NotEmpty(a.t, object, msgAndArgs...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// require.Len(mySlice, 3, "The size of slice is not 3")
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
Len(a.t, object, length, msgAndArgs...)
}
// True asserts that the specified value is true.
//
// require.True(myBool, "myBool should be true")
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
True(a.t, value, msgAndArgs...)
}
// False asserts that the specified value is true.
//
// require.False(myBool, "myBool should be false")
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
False(a.t, value, msgAndArgs...)
}
// NotEqual asserts that the specified values are NOT equal.
//
// require.NotEqual(obj1, obj2, "two objects shouldn't be equal")
func (a *Assertions) NotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
NotEqual(a.t, expected, actual, msgAndArgs...)
}
// Contains asserts that the specified string contains the specified substring.
//
// require.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
func (a *Assertions) Contains(s, contains interface{}, msgAndArgs ...interface{}) {
Contains(a.t, s, contains, msgAndArgs...)
}
// NotContains asserts that the specified string does NOT contain the specified substring.
//
// require.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
func (a *Assertions) NotContains(s, contains interface{}, msgAndArgs ...interface{}) {
NotContains(a.t, s, contains, msgAndArgs...)
}
// Uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
Condition(a.t, comp, msgAndArgs...)
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// require.Panics(func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
Panics(a.t, f, msgAndArgs...)
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// require.NotPanics(func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
NotPanics(a.t, f, msgAndArgs...)
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// require.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
func (a *Assertions) WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
// InDelta asserts that the two numerals are within delta of each other.
//
// require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
func (a *Assertions) InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if require.NoError(err) {
// require.Equal(actualObj, expectedObj)
// }
func (a *Assertions) NoError(theError error, msgAndArgs ...interface{}) {
NoError(a.t, theError, msgAndArgs...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if require.Error(err, "An error was expected") {
// require.Equal(err, expectedError)
// }
func (a *Assertions) Error(theError error, msgAndArgs ...interface{}) {
Error(a.t, theError, msgAndArgs...)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// if require.Error(err, "An error was expected") {
// require.Equal(err, expectedError)
// }
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
EqualError(a.t, theError, errString, msgAndArgs...)
}
// Regexp asserts that a specified regexp matches a string.
//
// require.Regexp(t, regexp.MustCompile("start"), "it's starting")
// require.Regexp(t, "start...$", "it's not starting")
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
Regexp(a.t, rx, str, msgAndArgs...)
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// require.NotRegexp(t, "^start", "it's not starting")
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
NotRegexp(a.t, rx, str, msgAndArgs...)
}

View File

@ -0,0 +1,260 @@
package require
import (
"errors"
"testing"
"time"
)
func TestImplementsWrapper(t *testing.T) {
require := New(t)
require.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Implements((*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestIsTypeWrapper(t *testing.T) {
require := New(t)
require.IsType(new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.IsType(new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEqualWrapper(t *testing.T) {
require := New(t)
require.Equal(1, 1)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Equal(1, 2)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotEqualWrapper(t *testing.T) {
require := New(t)
require.NotEqual(1, 2)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotEqual(2, 2)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestExactlyWrapper(t *testing.T) {
require := New(t)
a := float32(1)
b := float32(1)
c := float64(1)
require.Exactly(a, b)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Exactly(a, c)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotNilWrapper(t *testing.T) {
require := New(t)
require.NotNil(t, new(AssertionTesterConformingObject))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotNil(nil)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNilWrapper(t *testing.T) {
require := New(t)
require.Nil(nil)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Nil(new(AssertionTesterConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestTrueWrapper(t *testing.T) {
require := New(t)
require.True(true)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.True(false)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestFalseWrapper(t *testing.T) {
require := New(t)
require.False(false)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.False(true)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestContainsWrapper(t *testing.T) {
require := New(t)
require.Contains("Hello World", "Hello")
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Contains("Hello World", "Salut")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotContainsWrapper(t *testing.T) {
require := New(t)
require.NotContains("Hello World", "Hello!")
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotContains("Hello World", "Hello")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestPanicsWrapper(t *testing.T) {
require := New(t)
require.Panics(func() {
panic("Panic!")
})
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Panics(func() {})
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotPanicsWrapper(t *testing.T) {
require := New(t)
require.NotPanics(func() {})
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotPanics(func() {
panic("Panic!")
})
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNoErrorWrapper(t *testing.T) {
require := New(t)
require.NoError(nil)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NoError(errors.New("some error"))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestErrorWrapper(t *testing.T) {
require := New(t)
require.Error(errors.New("some error"))
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Error(nil)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEqualErrorWrapper(t *testing.T) {
require := New(t)
require.EqualError(errors.New("some error"), "some error")
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.EqualError(errors.New("some error"), "Not some error")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEmptyWrapper(t *testing.T) {
require := New(t)
require.Empty("")
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.Empty("x")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotEmptyWrapper(t *testing.T) {
require := New(t)
require.NotEmpty("x")
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.NotEmpty("")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestWithinDurationWrapper(t *testing.T) {
require := New(t)
a := time.Now()
b := a.Add(10 * time.Second)
require.WithinDuration(a, b, 15*time.Second)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.WithinDuration(a, b, 5*time.Second)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestInDeltaWrapper(t *testing.T) {
require := New(t)
require.InDelta(1.001, 1, 0.01)
mockT := new(MockT)
mockRequire := New(mockT)
mockRequire.InDelta(1, 2, 0.5)
if !mockT.Failed {
t.Error("Check should fail")
}
}

View File

@ -0,0 +1,271 @@
package require
import (
"time"
"github.com/stretchr/testify/assert"
)
type TestingT interface {
Errorf(format string, args ...interface{})
FailNow()
}
// Fail reports a failure through
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
assert.Fail(t, failureMessage, msgAndArgs...)
t.FailNow()
}
// Implements asserts that an object is implemented by the specified interface.
//
// require.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
t.FailNow()
}
}
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if !assert.IsType(t, expectedType, object, msgAndArgs...) {
t.FailNow()
}
}
// Equal asserts that two objects are equal.
//
// require.Equal(t, 123, 123, "123 and 123 should be equal")
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.Equal(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// EqualValues asserts that two objects are equal or convertable to each other.
//
// require.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.EqualValues(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// Exactly asserts that two objects are equal is value and type.
//
// require.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.Exactly(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// NotNil asserts that the specified object is not nil.
//
// require.NotNil(t, err, "err should be something")
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.NotNil(t, object, msgAndArgs...) {
t.FailNow()
}
}
// Nil asserts that the specified object is nil.
//
// require.Nil(t, err, "err should be nothing")
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.Nil(t, object, msgAndArgs...) {
t.FailNow()
}
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.Empty(t, object, msgAndArgs...) {
t.FailNow()
}
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// require.NotEmpty(t, obj)
// require.Equal(t, "one", obj[0])
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.NotEmpty(t, object, msgAndArgs...) {
t.FailNow()
}
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// require.Len(t, mySlice, 3, "The size of slice is not 3")
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
if !assert.Len(t, object, length, msgAndArgs...) {
t.FailNow()
}
}
// True asserts that the specified value is true.
//
// require.True(t, myBool, "myBool should be true")
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
if !assert.True(t, value, msgAndArgs...) {
t.FailNow()
}
}
// False asserts that the specified value is true.
//
// require.False(t, myBool, "myBool should be false")
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
if !assert.False(t, value, msgAndArgs...) {
t.FailNow()
}
}
// NotEqual asserts that the specified values are NOT equal.
//
// require.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// Contains asserts that the specified string contains the specified substring.
//
// require.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
if !assert.Contains(t, s, contains, msgAndArgs...) {
t.FailNow()
}
}
// NotContains asserts that the specified string does NOT contain the specified substring.
//
// require.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) {
if !assert.NotContains(t, s, contains, msgAndArgs...) {
t.FailNow()
}
}
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
if !assert.Condition(t, comp, msgAndArgs...) {
t.FailNow()
}
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// require.Panics(t, func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if !assert.Panics(t, f, msgAndArgs...) {
t.FailNow()
}
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// require.NotPanics(t, func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if !assert.NotPanics(t, f, msgAndArgs...) {
t.FailNow()
}
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
t.FailNow()
}
}
// InDelta asserts that the two numerals are within delta of each other.
//
// require.InDelta(t, math.Pi, (22 / 7.0), 0.01)
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
t.FailNow()
}
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
t.FailNow()
}
}
// Regexp asserts that a specified regexp matches a string.
//
// require.Regexp(t, regexp.MustCompile("start"), "it's starting")
// require.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if !assert.Regexp(t, rx, str, msgAndArgs...) {
t.FailNow()
}
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// require.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if !assert.NotRegexp(t, rx, str, msgAndArgs...) {
t.FailNow()
}
}
/*
Errors
*/
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// require.NoError(t, err)
// require.Equal(t, actualObj, expectedObj)
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
if !assert.NoError(t, err, msgAndArgs...) {
t.FailNow()
}
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// require.Error(t, err, "An error was expected")
// require.Equal(t, err, expectedError)
// }
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
if !assert.Error(t, err, msgAndArgs...) {
t.FailNow()
}
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// require.Error(t, err, "An error was expected")
// require.Equal(t, err, expectedError)
// }
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
if !assert.EqualError(t, theError, errString, msgAndArgs...) {
t.FailNow()
}
}

View File

@ -0,0 +1,266 @@
package require
import (
"errors"
"testing"
"time"
)
// AssertionTesterInterface defines an interface to be used for testing assertion methods
type AssertionTesterInterface interface {
TestMethod()
}
// AssertionTesterConformingObject is an object that conforms to the AssertionTesterInterface interface
type AssertionTesterConformingObject struct {
}
func (a *AssertionTesterConformingObject) TestMethod() {
}
// AssertionTesterNonConformingObject is an object that does not conform to the AssertionTesterInterface interface
type AssertionTesterNonConformingObject struct {
}
type MockT struct {
Failed bool
}
func (t *MockT) FailNow() {
t.Failed = true
}
func (t *MockT) Errorf(format string, args ...interface{}) {
_, _ = format, args
}
func TestImplements(t *testing.T) {
Implements(t, (*AssertionTesterInterface)(nil), new(AssertionTesterConformingObject))
mockT := new(MockT)
Implements(mockT, (*AssertionTesterInterface)(nil), new(AssertionTesterNonConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestIsType(t *testing.T) {
IsType(t, new(AssertionTesterConformingObject), new(AssertionTesterConformingObject))
mockT := new(MockT)
IsType(mockT, new(AssertionTesterConformingObject), new(AssertionTesterNonConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEqual(t *testing.T) {
Equal(t, 1, 1)
mockT := new(MockT)
Equal(mockT, 1, 2)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotEqual(t *testing.T) {
NotEqual(t, 1, 2)
mockT := new(MockT)
NotEqual(mockT, 2, 2)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestExactly(t *testing.T) {
a := float32(1)
b := float32(1)
c := float64(1)
Exactly(t, a, b)
mockT := new(MockT)
Exactly(mockT, a, c)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotNil(t *testing.T) {
NotNil(t, new(AssertionTesterConformingObject))
mockT := new(MockT)
NotNil(mockT, nil)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNil(t *testing.T) {
Nil(t, nil)
mockT := new(MockT)
Nil(mockT, new(AssertionTesterConformingObject))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestTrue(t *testing.T) {
True(t, true)
mockT := new(MockT)
True(mockT, false)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestFalse(t *testing.T) {
False(t, false)
mockT := new(MockT)
False(mockT, true)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestContains(t *testing.T) {
Contains(t, "Hello World", "Hello")
mockT := new(MockT)
Contains(mockT, "Hello World", "Salut")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotContains(t *testing.T) {
NotContains(t, "Hello World", "Hello!")
mockT := new(MockT)
NotContains(mockT, "Hello World", "Hello")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestPanics(t *testing.T) {
Panics(t, func() {
panic("Panic!")
})
mockT := new(MockT)
Panics(mockT, func() {})
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotPanics(t *testing.T) {
NotPanics(t, func() {})
mockT := new(MockT)
NotPanics(mockT, func() {
panic("Panic!")
})
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNoError(t *testing.T) {
NoError(t, nil)
mockT := new(MockT)
NoError(mockT, errors.New("some error"))
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestError(t *testing.T) {
Error(t, errors.New("some error"))
mockT := new(MockT)
Error(mockT, nil)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEqualError(t *testing.T) {
EqualError(t, errors.New("some error"), "some error")
mockT := new(MockT)
EqualError(mockT, errors.New("some error"), "Not some error")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestEmpty(t *testing.T) {
Empty(t, "")
mockT := new(MockT)
Empty(mockT, "x")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestNotEmpty(t *testing.T) {
NotEmpty(t, "x")
mockT := new(MockT)
NotEmpty(mockT, "")
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestWithinDuration(t *testing.T) {
a := time.Now()
b := a.Add(10 * time.Second)
WithinDuration(t, a, b, 15*time.Second)
mockT := new(MockT)
WithinDuration(mockT, a, b, 5*time.Second)
if !mockT.Failed {
t.Error("Check should fail")
}
}
func TestInDelta(t *testing.T) {
InDelta(t, 1.001, 1, 0.01)
mockT := new(MockT)
InDelta(mockT, 1, 2, 0.5)
if !mockT.Failed {
t.Error("Check should fail")
}
}

View File

@ -0,0 +1,222 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed 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 kubelet
import (
"sort"
"sync"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
docker "github.com/fsouza/go-dockerclient"
"github.com/golang/glog"
)
// Manages lifecycle of all images.
//
// Class is thread-safe.
type imageManager interface {
// Starts the image manager.
Start() error
// Tries to free bytesToFree worth of images on the disk.
//
// Returns the number of bytes free and an error if any occured. The number of
// bytes freed is always returned.
// Note that error may be nil and the number of bytes free may be less
// than bytesToFree.
FreeSpace(bytesToFree int64) (int64, error)
// TODO(vmarmol): Have this subsume pulls as well.
}
type realImageManager struct {
// Connection to the Docker daemon.
dockerClient dockertools.DockerInterface
// Records of images and their use.
imageRecords map[string]*imageRecord
// Lock for imageRecords.
imageRecordsLock sync.Mutex
}
// Information about the images we track.
type imageRecord struct {
// Time when this image was first detected.
detected time.Time
// Time when we last saw this image being used.
lastUsed time.Time
// Size of the image in bytes.
size int64
}
func newImageManager(dockerClient dockertools.DockerInterface) imageManager {
return &realImageManager{
dockerClient: dockerClient,
imageRecords: make(map[string]*imageRecord),
}
}
func (self *realImageManager) Start() error {
// Initial detection make detected time "unknown" in the past.
var zero time.Time
err := self.detectImages(zero)
if err != nil {
return err
}
util.Forever(func() {
err := self.detectImages(time.Now())
if err != nil {
glog.Warningf("[ImageManager] Failed to monitor images: %v", err)
}
}, 5*time.Minute)
return nil
}
func (self *realImageManager) detectImages(detected time.Time) error {
images, err := self.dockerClient.ListImages(docker.ListImagesOptions{})
if err != nil {
return err
}
containers, err := self.dockerClient.ListContainers(docker.ListContainersOptions{
All: true,
})
if err != nil {
return err
}
// Make a set of images in use by containers.
imagesInUse := util.NewStringSet()
for _, container := range containers {
imagesInUse.Insert(container.Image)
}
// Add new images and record those being used.
now := time.Now()
currentImages := util.NewStringSet()
self.imageRecordsLock.Lock()
defer self.imageRecordsLock.Unlock()
for _, image := range images {
currentImages.Insert(image.ID)
// New image, set it as detected now.
if _, ok := self.imageRecords[image.ID]; !ok {
self.imageRecords[image.ID] = &imageRecord{
detected: detected,
}
}
// Set last used time to now if the image is being used.
if isImageUsed(&image, imagesInUse) {
self.imageRecords[image.ID].lastUsed = now
}
self.imageRecords[image.ID].size = image.VirtualSize
}
// Remove old images from our records.
for image := range self.imageRecords {
if !currentImages.Has(image) {
delete(self.imageRecords, image)
}
}
return nil
}
func (self *realImageManager) FreeSpace(bytesToFree int64) (int64, error) {
startTime := time.Now()
err := self.detectImages(startTime)
if err != nil {
return 0, err
}
self.imageRecordsLock.Lock()
defer self.imageRecordsLock.Unlock()
// Get all images in eviction order.
images := make([]evictionInfo, 0, len(self.imageRecords))
for image, record := range self.imageRecords {
images = append(images, evictionInfo{
id: image,
imageRecord: *record,
})
}
sort.Sort(byLastUsedAndDetected(images))
// Delete unused images until we've freed up enough space.
var lastErr error
spaceFreed := int64(0)
for _, image := range images {
// Images that are currently in used were given a newer lastUsed.
if image.lastUsed.After(startTime) {
break
}
// Remove image. Continue despite errors.
err := self.dockerClient.RemoveImage(image.id)
if err != nil {
lastErr = err
continue
}
delete(self.imageRecords, image.id)
spaceFreed += image.size
if spaceFreed >= bytesToFree {
break
}
}
return spaceFreed, lastErr
}
type evictionInfo struct {
id string
imageRecord
}
type byLastUsedAndDetected []evictionInfo
func (self byLastUsedAndDetected) Len() int { return len(self) }
func (self byLastUsedAndDetected) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
func (self byLastUsedAndDetected) Less(i, j int) bool {
// Sort by last used, break ties by detected.
if self[i].lastUsed.Equal(self[j].lastUsed) {
return self[i].detected.Before(self[j].detected)
} else {
return self[i].lastUsed.Before(self[j].lastUsed)
}
}
func isImageUsed(image *docker.APIImages, imagesInUse util.StringSet) bool {
// Check the image ID and all the RepoTags.
if _, ok := imagesInUse[image.ID]; ok {
return true
}
for _, tag := range image.RepoTags {
if _, ok := imagesInUse[tag]; ok {
return true
}
}
return false
}

View File

@ -0,0 +1,301 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed 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 kubelet
import (
"fmt"
"testing"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
docker "github.com/fsouza/go-dockerclient"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var zero time.Time
func newRealImageManager(dockerClient dockertools.DockerInterface) *realImageManager {
return newImageManager(dockerClient).(*realImageManager)
}
// Returns the name of the image with the given ID.
func imageName(id int) string {
return fmt.Sprintf("image-%d", id)
}
// Make an image with the specified ID.
func makeImage(id int, size int64) docker.APIImages {
return docker.APIImages{
ID: imageName(id),
VirtualSize: size,
}
}
// Make a container with the specified ID. It will use the image with the same ID.
func makeContainer(id int) docker.APIContainers {
return docker.APIContainers{
ID: fmt.Sprintf("container-%d", id),
Image: imageName(id),
}
}
func TestDetectImagesInitialDetect(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(1),
},
}
manager := newRealImageManager(fakeDocker)
startTime := time.Now().Add(-time.Millisecond)
err := manager.detectImages(zero)
assert := assert.New(t)
require.Nil(t, err)
assert.Len(manager.imageRecords, 2)
noContainer, ok := manager.imageRecords[imageName(0)]
require.True(t, ok)
assert.Equal(zero, noContainer.detected)
assert.Equal(zero, noContainer.lastUsed)
withContainer, ok := manager.imageRecords[imageName(1)]
require.True(t, ok)
assert.Equal(zero, withContainer.detected)
assert.True(withContainer.lastUsed.After(startTime))
}
func TestDetectImagesWithNewImage(t *testing.T) {
// Just one image initially.
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(1),
},
}
manager := newRealImageManager(fakeDocker)
err := manager.detectImages(zero)
assert := assert.New(t)
require.Nil(t, err)
assert.Len(manager.imageRecords, 2)
// Add a new image.
fakeDocker.Images = []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 1024),
makeImage(2, 1024),
}
detectedTime := zero.Add(time.Second)
startTime := time.Now().Add(-time.Millisecond)
err = manager.detectImages(detectedTime)
require.Nil(t, err)
assert.Len(manager.imageRecords, 3)
noContainer, ok := manager.imageRecords[imageName(0)]
require.True(t, ok)
assert.Equal(zero, noContainer.detected)
assert.Equal(zero, noContainer.lastUsed)
withContainer, ok := manager.imageRecords[imageName(1)]
require.True(t, ok)
assert.Equal(zero, withContainer.detected)
assert.True(withContainer.lastUsed.After(startTime))
newContainer, ok := manager.imageRecords[imageName(2)]
require.True(t, ok)
assert.Equal(detectedTime, newContainer.detected)
assert.Equal(zero, noContainer.lastUsed)
}
func TestDetectImagesContainerStopped(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(1),
},
}
manager := newRealImageManager(fakeDocker)
err := manager.detectImages(zero)
assert := assert.New(t)
require.Nil(t, err)
assert.Len(manager.imageRecords, 2)
withContainer, ok := manager.imageRecords[imageName(1)]
require.True(t, ok)
// Simulate container being stopped.
fakeDocker.ContainerList = []docker.APIContainers{}
err = manager.detectImages(time.Now())
require.Nil(t, err)
assert.Len(manager.imageRecords, 2)
container1, ok := manager.imageRecords[imageName(0)]
require.True(t, ok)
assert.Equal(zero, container1.detected)
assert.Equal(zero, container1.lastUsed)
container2, ok := manager.imageRecords[imageName(1)]
require.True(t, ok)
assert.Equal(zero, container2.detected)
assert.True(container2.lastUsed.Equal(withContainer.lastUsed))
}
func TestDetectImagesWithRemovedImages(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(1),
},
}
manager := newRealImageManager(fakeDocker)
err := manager.detectImages(zero)
assert := assert.New(t)
require.Nil(t, err)
assert.Len(manager.imageRecords, 2)
// Simulate both images being removed.
fakeDocker.Images = []docker.APIImages{}
err = manager.detectImages(time.Now())
require.Nil(t, err)
assert.Len(manager.imageRecords, 0)
}
func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(1),
},
RemovedImages: util.NewStringSet(),
}
manager := newRealImageManager(fakeDocker)
spaceFreed, err := manager.FreeSpace(2048)
assert := assert.New(t)
require.Nil(t, err)
assert.Equal(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
}
func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
},
ContainerList: []docker.APIContainers{
makeContainer(0),
makeContainer(1),
},
RemovedImages: util.NewStringSet(),
}
manager := newRealImageManager(fakeDocker)
// Make 1 be more recently used than 0.
require.Nil(t, manager.detectImages(zero))
fakeDocker.ContainerList = []docker.APIContainers{
makeContainer(1),
}
require.Nil(t, manager.detectImages(time.Now()))
fakeDocker.ContainerList = []docker.APIContainers{}
require.Nil(t, manager.detectImages(time.Now()))
require.Len(t, manager.imageRecords, 2)
spaceFreed, err := manager.FreeSpace(1024)
assert := assert.New(t)
require.Nil(t, err)
assert.Equal(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
}
func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
},
ContainerList: []docker.APIContainers{
makeContainer(0),
},
RemovedImages: util.NewStringSet(),
}
manager := newRealImageManager(fakeDocker)
// Make 1 more recently detected but used at the same time as 0.
require.Nil(t, manager.detectImages(zero))
fakeDocker.Images = []docker.APIImages{
makeImage(0, 1024),
makeImage(1, 2048),
}
fakeDocker.ContainerList = []docker.APIContainers{
makeContainer(0),
makeContainer(1),
}
require.Nil(t, manager.detectImages(time.Now()))
fakeDocker.ContainerList = []docker.APIContainers{}
require.Nil(t, manager.detectImages(time.Now()))
require.Len(t, manager.imageRecords, 2)
spaceFreed, err := manager.FreeSpace(1024)
assert := assert.New(t)
require.Nil(t, err)
assert.Equal(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
}
func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
fakeDocker := &dockertools.FakeDockerClient{
Images: []docker.APIImages{
makeImage(0, 1024),
{
ID: "5678",
RepoTags: []string{"potato", "salad"},
VirtualSize: 2048,
},
},
ContainerList: []docker.APIContainers{
{
ID: "c5678",
Image: "salad",
},
},
RemovedImages: util.NewStringSet(),
}
manager := newRealImageManager(fakeDocker)
spaceFreed, err := manager.FreeSpace(1024)
assert := assert.New(t)
require.Nil(t, err)
assert.Equal(1024, spaceFreed)
assert.Len(fakeDocker.RemovedImages, 1)
assert.True(fakeDocker.RemovedImages.Has(imageName(0)))
}