Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reenable coverage and race detection on Travis #3365

Merged
merged 4 commits into from
Jan 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ install:
- ./hack/build-go.sh

script:
- KUBE_TIMEOUT='-timeout 60s' ./hack/test-go.sh
- KUBE_RACE="-race" KUBE_COVER="-cover -covermode=atomic" KUBE_TIMEOUT='-timeout 60s' ./hack/test-go.sh
- PATH=$HOME/gopath/bin:./third_party/etcd:$PATH ./hack/test-cmd.sh
- PATH=$HOME/gopath/bin:./third_party/etcd:$PATH ./hack/test-integration.sh

Expand Down
4 changes: 2 additions & 2 deletions hack/test-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ kube::test::find_pkgs() {
}

# -covermode=atomic becomes default with -race in Go >=1.3
KUBE_COVER="" #${KUBE_COVER:--cover -covermode=atomic}
KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 120s}
KUBE_RACE="" #${KUBE_RACE:--race}
KUBE_COVER=${KUBE_COVER:-} # use KUBE_COVER="-cover -covermode=atomic" for full coverage
KUBE_RACE=${KUBE_RACE:-} # use KUBE_RACE="-race" to enable race testing

kube::test::usage() {
kube::log::usage_from_stdin <<EOF
Expand Down
1 change: 1 addition & 0 deletions hack/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ kube::etcd::start

kube::log::status "Running integration test cases"
KUBE_GOFLAGS="-tags 'integration no-docker' " \
KUBE_RACE="-race" \
"${KUBE_ROOT}/hack/test-go.sh" test/integration

kube::log::status "Running integration test scenario"
Expand Down
6 changes: 5 additions & 1 deletion pkg/client/record/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import (
"github.com/golang/glog"
)

// retryEventSleep is the time between record failures to retry. Available for test alteration.
var retryEventSleep = 1 * time.Second

// EventRecorder knows how to store events (client.Client implements it.)
// EventRecorder must respect the namespace that will be embedded in 'event'.
// It is assumed that EventRecorder will return the same sorts of errors as
Expand All @@ -41,6 +44,7 @@ type EventRecorder interface {
// StartRecording starts sending events to recorder. Call once while initializing
// your binary. Subsequent calls will be ignored. The return value can be ignored
// or used to stop recording, if desired.
// TODO: make me an object with parameterizable queue length and retry interval
func StartRecording(recorder EventRecorder, source api.EventSource) watch.Interface {
return GetEvents(func(event *api.Event) {
// Make a copy before modification, because there could be multiple listeners.
Expand Down Expand Up @@ -80,7 +84,7 @@ func StartRecording(recorder EventRecorder, source api.EventSource) watch.Interf
break
}
glog.Errorf("Unable to write event: '%v' (will retry in 1 second)", err)
time.Sleep(1 * time.Second)
time.Sleep(retryEventSleep)
}
})
}
Expand Down
22 changes: 13 additions & 9 deletions pkg/client/record/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package record_test
package record

import (
"fmt"
"reflect"
"strings"
"testing"
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)

func init() {
retryEventSleep = 1 * time.Microsecond
}

type testEventRecorder struct {
OnEvent func(e *api.Event) (*api.Event, error)
}
Expand Down Expand Up @@ -142,16 +146,16 @@ func TestEventf(t *testing.T) {
return event, nil
},
}
recorder := record.StartRecording(&testEvents, api.EventSource{Component: "eventTest"})
logger := record.StartLogging(t.Logf) // Prove that it is useful
logger2 := record.StartLogging(func(formatter string, args ...interface{}) {
recorder := StartRecording(&testEvents, api.EventSource{Component: "eventTest"})
logger := StartLogging(t.Logf) // Prove that it is useful
logger2 := StartLogging(func(formatter string, args ...interface{}) {
if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
called <- struct{}{}
})

record.Eventf(item.obj, item.status, item.reason, item.messageFmt, item.elements...)
Eventf(item.obj, item.status, item.reason, item.messageFmt, item.elements...)

<-called
<-called
Expand Down Expand Up @@ -204,7 +208,7 @@ func TestWriteEventError(t *testing.T) {
}
done := make(chan struct{})

defer record.StartRecording(
defer StartRecording(
&testEventRecorder{
OnEvent: func(event *api.Event) (*api.Event, error) {
if event.Message == "finished" {
Expand All @@ -227,9 +231,9 @@ func TestWriteEventError(t *testing.T) {
).Stop()

for caseName := range table {
record.Event(ref, "Status", "Reason", caseName)
Event(ref, "Status", "Reason", caseName)
}
record.Event(ref, "Status", "Reason", "finished")
Event(ref, "Status", "Reason", "finished")
<-done

for caseName, item := range table {
Expand Down
8 changes: 7 additions & 1 deletion pkg/kubecfg/kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ func SaveNamespaceInfo(path string, ns *NamespaceInfo) error {
return err
}

// extracted for test speed
var (
updatePollInterval = 5 * time.Second
updatePollTimeout = 300 * time.Second
)

// Update performs a rolling update of a collection of pods.
// 'name' points to a replication controller.
// 'client' is used for updating pods.
Expand Down Expand Up @@ -149,7 +155,7 @@ func Update(ctx api.Context, name string, client client.Interface, updatePeriod
}
time.Sleep(updatePeriod)
}
return wait.Poll(time.Second*5, time.Second*300, func() (bool, error) {
return wait.Poll(updatePollInterval, updatePollTimeout, func() (bool, error) {
podList, err := client.Pods(api.Namespace(ctx)).List(s)
if err != nil {
return false, err
Expand Down
5 changes: 5 additions & 0 deletions pkg/kubecfg/kubecfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"os"
"reflect"
"testing"
"time"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
Expand All @@ -35,6 +36,10 @@ func validateAction(expectedAction, actualAction client.FakeAction, t *testing.T
}
}

func init() {
updatePollInterval = 1 * time.Millisecond
}

func TestUpdateWithPods(t *testing.T) {
fakeClient := client.Fake{
PodsList: api.PodList{
Expand Down
19 changes: 12 additions & 7 deletions plugin/pkg/scheduler/factory/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSe
podBackoff := podBackoff{
perPodBackoff: map[string]*backoffEntry{},
clock: realClock{},

defaultDuration: 1 * time.Second,
maxDuration: 60 * time.Second,
}

return &scheduler.Config{
Expand Down Expand Up @@ -245,17 +248,19 @@ type backoffEntry struct {
}

type podBackoff struct {
perPodBackoff map[string]*backoffEntry
lock sync.Mutex
clock clock
perPodBackoff map[string]*backoffEntry
lock sync.Mutex
clock clock
defaultDuration time.Duration
maxDuration time.Duration
}

func (p *podBackoff) getEntry(podID string) *backoffEntry {
p.lock.Lock()
defer p.lock.Unlock()
entry, ok := p.perPodBackoff[podID]
if !ok {
entry = &backoffEntry{backoff: 1 * time.Second}
entry = &backoffEntry{backoff: p.defaultDuration}
p.perPodBackoff[podID] = entry
}
entry.lastUpdate = p.clock.Now()
Expand All @@ -266,8 +271,8 @@ func (p *podBackoff) getBackoff(podID string) time.Duration {
entry := p.getEntry(podID)
duration := entry.backoff
entry.backoff *= 2
if entry.backoff > 60*time.Second {
entry.backoff = 60 * time.Second
if entry.backoff > p.maxDuration {
entry.backoff = p.maxDuration
}
glog.V(4).Infof("Backing off %s for pod %s", duration.String(), podID)
return duration
Expand All @@ -282,7 +287,7 @@ func (p *podBackoff) gc() {
defer p.lock.Unlock()
now := p.clock.Now()
for podID, entry := range p.perPodBackoff {
if now.Sub(entry.lastUpdate) > 60*time.Second {
if now.Sub(entry.lastUpdate) > p.maxDuration {
delete(p.perPodBackoff, podID)
}
}
Expand Down
12 changes: 8 additions & 4 deletions plugin/pkg/scheduler/factory/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ func TestDefaultErrorFunc(t *testing.T) {
factory := NewConfigFactory(client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}))
queue := cache.NewFIFO()
podBackoff := podBackoff{
perPodBackoff: map[string]*backoffEntry{},
clock: &fakeClock{},
perPodBackoff: map[string]*backoffEntry{},
clock: &fakeClock{},
defaultDuration: 1 * time.Millisecond,
maxDuration: 1 * time.Second,
}
errFunc := factory.makeDefaultErrorFunc(&podBackoff, queue)

Expand Down Expand Up @@ -203,8 +205,10 @@ func TestBind(t *testing.T) {
func TestBackoff(t *testing.T) {
clock := fakeClock{}
backoff := podBackoff{
perPodBackoff: map[string]*backoffEntry{},
clock: &clock,
perPodBackoff: map[string]*backoffEntry{},
clock: &clock,
defaultDuration: 1 * time.Second,
maxDuration: 60 * time.Second,
}

tests := []struct {
Expand Down