mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
Merge pull request #20137 from mqliang/fake-time
reuse fake clock in the kube repo for kubelet unit tests
This commit is contained in:
commit
ae5a6e86df
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -861,10 +861,6 @@
|
|||||||
"ImportPath": "github.com/spf13/pflag",
|
"ImportPath": "github.com/spf13/pflag",
|
||||||
"Rev": "08b1a584251b5b62f458943640fc8ebd4d50aaa5"
|
"Rev": "08b1a584251b5b62f458943640fc8ebd4d50aaa5"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/ssoroka/ttime",
|
|
||||||
"Rev": "881f221816e0300201ac24f6c31e54e3bb958de7"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/stretchr/objx",
|
"ImportPath": "github.com/stretchr/objx",
|
||||||
"Rev": "d40df0cc104c06eae2dfe03d7dddb83802d52f9a"
|
"Rev": "d40df0cc104c06eae2dfe03d7dddb83802d52f9a"
|
||||||
|
1
Godeps/LICENSES.md
generated
1
Godeps/LICENSES.md
generated
@ -84,7 +84,6 @@ github.com/Sirupsen/logrus | MITname
|
|||||||
github.com/skynetservices/skydns | MITname
|
github.com/skynetservices/skydns | MITname
|
||||||
github.com/spf13/cobra | Apache-2
|
github.com/spf13/cobra | Apache-2
|
||||||
github.com/spf13/pflag | spdxBSD3
|
github.com/spf13/pflag | spdxBSD3
|
||||||
github.com/ssoroka/ttime | UNKNOWN
|
|
||||||
github.com/stretchr/objx | MIT?
|
github.com/stretchr/objx | MIT?
|
||||||
github.com/stretchr/testify | MIT?
|
github.com/stretchr/testify | MIT?
|
||||||
github.com/syndtr/gocapability | spdxBSD2
|
github.com/syndtr/gocapability | spdxBSD2
|
||||||
|
42
Godeps/_workspace/src/github.com/ssoroka/ttime/README.md
generated
vendored
42
Godeps/_workspace/src/github.com/ssoroka/ttime/README.md
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
This is an experiment in making time easier to mock in Go tests.
|
|
||||||
|
|
||||||
You should be able to alias the ttime library to time to avoid having to change all your time.Now() methods to ttime.Now() throughout your code.
|
|
||||||
|
|
||||||
All methods return actual time.Time structs (if they were supposed to).
|
|
||||||
|
|
||||||
example code:
|
|
||||||
|
|
||||||
import (
|
|
||||||
time "github.com/ssoroka/ttime"
|
|
||||||
)
|
|
||||||
|
|
||||||
fmt.Printf("The starting time is %v", time.Now().UTC())
|
|
||||||
|
|
||||||
// in test this will not sleep at all, but it will advance the clock 5 seconds.
|
|
||||||
// in production, it's identical to time.Sleep
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
fmt.Printf("The time after sleeping for 5 seconds is %v", time.Now().UTC())
|
|
||||||
|
|
||||||
time.After(10 * time.Second, func() {
|
|
||||||
// This will execute after 10 seconds in production and immediately in tests.
|
|
||||||
fmt.Printf("It is now %v", time.Now().UTC())
|
|
||||||
})
|
|
||||||
|
|
||||||
example test:
|
|
||||||
|
|
||||||
func TestFreezingTime(t *testing.T) {
|
|
||||||
time.Freeze(time.Now()) // freeze the system clock, at least as far as ttime is concerned.
|
|
||||||
|
|
||||||
// or freeze time at a specific date/time (eg, test leap-year support!):
|
|
||||||
now, err := time.Parse(time.RFC3339, "2012-02-29T00:00:00Z")
|
|
||||||
if err != nil { panic("date time parse failed") }
|
|
||||||
time.Freeze(now)
|
|
||||||
defer time.Unfreeze()
|
|
||||||
|
|
||||||
// test leap-year-specific code
|
|
||||||
if !isLeapYear(time.Now()) {
|
|
||||||
t.Error("Oh no! isLeapYear is broken!")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("It is now %v", time.Now().UTC())
|
|
||||||
}
|
|
108
Godeps/_workspace/src/github.com/ssoroka/ttime/ttime.go
generated
vendored
108
Godeps/_workspace/src/github.com/ssoroka/ttime/ttime.go
generated
vendored
@ -1,108 +0,0 @@
|
|||||||
package ttime
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
var (
|
|
||||||
currentTime time.Time
|
|
||||||
timeFrozen bool
|
|
||||||
)
|
|
||||||
|
|
||||||
type Duration time.Duration
|
|
||||||
type Location time.Location
|
|
||||||
type Month time.Month
|
|
||||||
type ParseError time.ParseError
|
|
||||||
type Ticker time.Ticker
|
|
||||||
type Time time.Time
|
|
||||||
type Timer time.Timer
|
|
||||||
type Weekday time.Weekday
|
|
||||||
|
|
||||||
var (
|
|
||||||
// import a ton of constants so we can act like the time library.
|
|
||||||
Parse = time.Parse
|
|
||||||
ParseDuration = time.ParseDuration
|
|
||||||
Date = time.Date
|
|
||||||
ParseInLocation = time.ParseInLocation
|
|
||||||
FixedZone = time.FixedZone
|
|
||||||
LoadLocation = time.LoadLocation
|
|
||||||
Sunday = time.Sunday
|
|
||||||
Monday = time.Monday
|
|
||||||
Tuesday = time.Tuesday
|
|
||||||
Wednesday = time.Wednesday
|
|
||||||
Thursday = time.Thursday
|
|
||||||
Friday = time.Friday
|
|
||||||
Saturday = time.Saturday
|
|
||||||
ANSIC = time.ANSIC
|
|
||||||
UnixDate = time.UnixDate
|
|
||||||
RubyDate = time.RubyDate
|
|
||||||
RFC822 = time.RFC822
|
|
||||||
RFC822Z = time.RFC822Z
|
|
||||||
RFC850 = time.RFC850
|
|
||||||
RFC1123 = time.RFC1123
|
|
||||||
RFC1123Z = time.RFC1123Z
|
|
||||||
RFC3339 = time.RFC3339
|
|
||||||
RFC3339Nano = time.RFC3339Nano
|
|
||||||
Kitchen = time.Kitchen
|
|
||||||
Stamp = time.Stamp
|
|
||||||
StampMilli = time.StampMilli
|
|
||||||
StampMicro = time.StampMicro
|
|
||||||
StampNano = time.StampNano
|
|
||||||
// constants that I really should redefine:
|
|
||||||
NewTimer = time.NewTimer
|
|
||||||
NewTicker = time.NewTicker
|
|
||||||
Unix = time.Unix
|
|
||||||
)
|
|
||||||
|
|
||||||
func Freeze(t time.Time) {
|
|
||||||
currentTime = t
|
|
||||||
timeFrozen = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Unfreeze() {
|
|
||||||
timeFrozen = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsFrozen() bool {
|
|
||||||
return timeFrozen
|
|
||||||
}
|
|
||||||
|
|
||||||
func Now() time.Time {
|
|
||||||
if timeFrozen {
|
|
||||||
return currentTime
|
|
||||||
} else {
|
|
||||||
return time.Now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func After(d time.Duration) <-chan time.Time {
|
|
||||||
if timeFrozen {
|
|
||||||
currentTime = currentTime.Add(d)
|
|
||||||
c := make(chan time.Time, 1)
|
|
||||||
c <- currentTime
|
|
||||||
return c
|
|
||||||
} else {
|
|
||||||
return time.After(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Tick(d time.Duration) <-chan time.Time {
|
|
||||||
if timeFrozen {
|
|
||||||
c := make(chan time.Time, 1)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
currentTime = currentTime.Add(d)
|
|
||||||
c <- currentTime
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return c
|
|
||||||
} else {
|
|
||||||
return time.Tick(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sleep(d time.Duration) {
|
|
||||||
if timeFrozen && d > 0 {
|
|
||||||
currentTime = currentTime.Add(d)
|
|
||||||
} else {
|
|
||||||
time.Sleep(d)
|
|
||||||
}
|
|
||||||
}
|
|
@ -156,7 +156,7 @@ func (im *realImageManager) GetImageList() ([]kubecontainer.Image, error) {
|
|||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (im *realImageManager) detectImages(detected time.Time) error {
|
func (im *realImageManager) detectImages(detectTime time.Time) error {
|
||||||
images, err := im.runtime.ListImages()
|
images, err := im.runtime.ListImages()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -185,7 +185,7 @@ func (im *realImageManager) detectImages(detected time.Time) error {
|
|||||||
// New image, set it as detected now.
|
// New image, set it as detected now.
|
||||||
if _, ok := im.imageRecords[image.ID]; !ok {
|
if _, ok := im.imageRecords[image.ID]; !ok {
|
||||||
im.imageRecords[image.ID] = &imageRecord{
|
im.imageRecords[image.ID] = &imageRecord{
|
||||||
firstDetected: detected,
|
firstDetected: detectTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ func (im *realImageManager) GarbageCollect() error {
|
|||||||
if usagePercent >= im.policy.HighThresholdPercent {
|
if usagePercent >= im.policy.HighThresholdPercent {
|
||||||
amountToFree := usage - (int64(im.policy.LowThresholdPercent) * capacity / 100)
|
amountToFree := usage - (int64(im.policy.LowThresholdPercent) * capacity / 100)
|
||||||
glog.Infof("[ImageManager]: Disk usage on %q (%s) is at %d%% which is over the high threshold (%d%%). Trying to free %d bytes", fsInfo.Device, fsInfo.Mountpoint, usagePercent, im.policy.HighThresholdPercent, amountToFree)
|
glog.Infof("[ImageManager]: Disk usage on %q (%s) is at %d%% which is over the high threshold (%d%%). Trying to free %d bytes", fsInfo.Device, fsInfo.Mountpoint, usagePercent, im.policy.HighThresholdPercent, amountToFree)
|
||||||
freed, err := im.freeSpace(amountToFree)
|
freed, err := im.freeSpace(amountToFree, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -249,9 +249,8 @@ func (im *realImageManager) GarbageCollect() error {
|
|||||||
// bytes freed is always returned.
|
// bytes freed is always returned.
|
||||||
// Note that error may be nil and the number of bytes free may be less
|
// Note that error may be nil and the number of bytes free may be less
|
||||||
// than bytesToFree.
|
// than bytesToFree.
|
||||||
func (im *realImageManager) freeSpace(bytesToFree int64) (int64, error) {
|
func (im *realImageManager) freeSpace(bytesToFree int64, freeTime time.Time) (int64, error) {
|
||||||
startTime := time.Now()
|
err := im.detectImages(freeTime)
|
||||||
err := im.detectImages(startTime)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -274,13 +273,13 @@ func (im *realImageManager) freeSpace(bytesToFree int64) (int64, error) {
|
|||||||
spaceFreed := int64(0)
|
spaceFreed := int64(0)
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
// Images that are currently in used were given a newer lastUsed.
|
// Images that are currently in used were given a newer lastUsed.
|
||||||
if image.lastUsed.After(startTime) {
|
if image.lastUsed.After(freeTime) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid garbage collect the image if the image is not old enough.
|
// Avoid garbage collect the image if the image is not old enough.
|
||||||
// In such a case, the image may have just been pulled down, and will be used by a container right away.
|
// In such a case, the image may have just been pulled down, and will be used by a container right away.
|
||||||
if startTime.Sub(image.firstDetected) < im.minAge {
|
if freeTime.Sub(image.firstDetected) < im.minAge {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||||
"github.com/ssoroka/ttime"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/container"
|
"k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
|
"k8s.io/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var zero time.Time
|
var zero time.Time
|
||||||
@ -231,7 +231,7 @@ func TestFreeSpaceImagesInUseContainersAreIgnored(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceFreed, err := manager.freeSpace(2048)
|
spaceFreed, err := manager.freeSpace(2048, time.Now())
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(1024, spaceFreed)
|
assert.EqualValues(1024, spaceFreed)
|
||||||
@ -271,7 +271,7 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
|
|||||||
require.NoError(t, manager.detectImages(time.Now()))
|
require.NoError(t, manager.detectImages(time.Now()))
|
||||||
require.Equal(t, manager.imageRecordsLen(), 2)
|
require.Equal(t, manager.imageRecordsLen(), 2)
|
||||||
|
|
||||||
spaceFreed, err := manager.freeSpace(1024)
|
spaceFreed, err := manager.freeSpace(1024, time.Now())
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(1024, spaceFreed)
|
assert.EqualValues(1024, spaceFreed)
|
||||||
@ -302,7 +302,7 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
|
|||||||
require.NoError(t, manager.detectImages(time.Now()))
|
require.NoError(t, manager.detectImages(time.Now()))
|
||||||
require.Equal(t, manager.imageRecordsLen(), 2)
|
require.Equal(t, manager.imageRecordsLen(), 2)
|
||||||
|
|
||||||
spaceFreed, err := manager.freeSpace(1024)
|
spaceFreed, err := manager.freeSpace(1024, time.Now())
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(2048, spaceFreed)
|
assert.EqualValues(2048, spaceFreed)
|
||||||
@ -330,7 +330,7 @@ func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceFreed, err := manager.freeSpace(1024)
|
spaceFreed, err := manager.freeSpace(1024, time.Now())
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(1024, spaceFreed)
|
assert.EqualValues(1024, spaceFreed)
|
||||||
@ -431,18 +431,20 @@ func TestGarbageCollectImageNotOldEnough(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, manager.detectImages(ttime.Now()))
|
fakeClock := util.FakeClock{Time: time.Now()}
|
||||||
|
fmt.Println(fakeClock.Now())
|
||||||
|
require.NoError(t, manager.detectImages(fakeClock.Now()))
|
||||||
require.Equal(t, manager.imageRecordsLen(), 2)
|
require.Equal(t, manager.imageRecordsLen(), 2)
|
||||||
// no space freed since one image is in used, and another one is not old enough
|
// no space freed since one image is in used, and another one is not old enough
|
||||||
spaceFreed, err := manager.freeSpace(1024)
|
spaceFreed, err := manager.freeSpace(1024, fakeClock.Now())
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(0, spaceFreed)
|
assert.EqualValues(0, spaceFreed)
|
||||||
assert.Len(fakeRuntime.ImageList, 2)
|
assert.Len(fakeRuntime.ImageList, 2)
|
||||||
|
|
||||||
// sleep 1 minute, then 1 image will be garbage collected
|
// move clock by minAge duration, then 1 image will be garbage collected
|
||||||
ttime.Sleep(defaultGCAge)
|
fakeClock.Step(manager.minAge)
|
||||||
spaceFreed, err = manager.freeSpace(1024)
|
spaceFreed, err = manager.freeSpace(1024, fakeClock.Now())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(1024, spaceFreed)
|
assert.EqualValues(1024, spaceFreed)
|
||||||
assert.Len(fakeRuntime.ImageList, 1)
|
assert.Len(fakeRuntime.ImageList, 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user