mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +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",
|
||||
"Rev": "08b1a584251b5b62f458943640fc8ebd4d50aaa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ssoroka/ttime",
|
||||
"Rev": "881f221816e0300201ac24f6c31e54e3bb958de7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/objx",
|
||||
"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/spf13/cobra | Apache-2
|
||||
github.com/spf13/pflag | spdxBSD3
|
||||
github.com/ssoroka/ttime | UNKNOWN
|
||||
github.com/stretchr/objx | MIT?
|
||||
github.com/stretchr/testify | MIT?
|
||||
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
|
||||
}
|
||||
|
||||
func (im *realImageManager) detectImages(detected time.Time) error {
|
||||
func (im *realImageManager) detectImages(detectTime time.Time) error {
|
||||
images, err := im.runtime.ListImages()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -185,7 +185,7 @@ func (im *realImageManager) detectImages(detected time.Time) error {
|
||||
// New image, set it as detected now.
|
||||
if _, ok := im.imageRecords[image.ID]; !ok {
|
||||
im.imageRecords[image.ID] = &imageRecord{
|
||||
firstDetected: detected,
|
||||
firstDetected: detectTime,
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ func (im *realImageManager) GarbageCollect() error {
|
||||
if usagePercent >= im.policy.HighThresholdPercent {
|
||||
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)
|
||||
freed, err := im.freeSpace(amountToFree)
|
||||
freed, err := im.freeSpace(amountToFree, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -249,9 +249,8 @@ func (im *realImageManager) GarbageCollect() error {
|
||||
// bytes freed is always returned.
|
||||
// Note that error may be nil and the number of bytes free may be less
|
||||
// than bytesToFree.
|
||||
func (im *realImageManager) freeSpace(bytesToFree int64) (int64, error) {
|
||||
startTime := time.Now()
|
||||
err := im.detectImages(startTime)
|
||||
func (im *realImageManager) freeSpace(bytesToFree int64, freeTime time.Time) (int64, error) {
|
||||
err := im.detectImages(freeTime)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -274,13 +273,13 @@ func (im *realImageManager) freeSpace(bytesToFree int64) (int64, error) {
|
||||
spaceFreed := int64(0)
|
||||
for _, image := range images {
|
||||
// Images that are currently in used were given a newer lastUsed.
|
||||
if image.lastUsed.After(startTime) {
|
||||
if image.lastUsed.After(freeTime) {
|
||||
break
|
||||
}
|
||||
|
||||
// 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.
|
||||
if startTime.Sub(image.firstDetected) < im.minAge {
|
||||
if freeTime.Sub(image.firstDetected) < im.minAge {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,12 @@ import (
|
||||
"time"
|
||||
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
"github.com/ssoroka/ttime"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
"k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(1024, spaceFreed)
|
||||
@ -271,7 +271,7 @@ func TestFreeSpaceRemoveByLeastRecentlyUsed(t *testing.T) {
|
||||
require.NoError(t, manager.detectImages(time.Now()))
|
||||
require.Equal(t, manager.imageRecordsLen(), 2)
|
||||
|
||||
spaceFreed, err := manager.freeSpace(1024)
|
||||
spaceFreed, err := manager.freeSpace(1024, time.Now())
|
||||
assert := assert.New(t)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(1024, spaceFreed)
|
||||
@ -302,7 +302,7 @@ func TestFreeSpaceTiesBrokenByDetectedTime(t *testing.T) {
|
||||
require.NoError(t, manager.detectImages(time.Now()))
|
||||
require.Equal(t, manager.imageRecordsLen(), 2)
|
||||
|
||||
spaceFreed, err := manager.freeSpace(1024)
|
||||
spaceFreed, err := manager.freeSpace(1024, time.Now())
|
||||
assert := assert.New(t)
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
// 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)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(0, spaceFreed)
|
||||
assert.Len(fakeRuntime.ImageList, 2)
|
||||
|
||||
// sleep 1 minute, then 1 image will be garbage collected
|
||||
ttime.Sleep(defaultGCAge)
|
||||
spaceFreed, err = manager.freeSpace(1024)
|
||||
// move clock by minAge duration, then 1 image will be garbage collected
|
||||
fakeClock.Step(manager.minAge)
|
||||
spaceFreed, err = manager.freeSpace(1024, fakeClock.Now())
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(1024, spaceFreed)
|
||||
assert.Len(fakeRuntime.ImageList, 1)
|
||||
|
Loading…
Reference in New Issue
Block a user