blob: 704d19aac708786957a291b3c630ccd2deb84055 [file] [edit]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package testingutil_test
import (
"context"
"errors"
"fmt"
"strings"
gotesting "testing"
"time"
"chromiumos/tast/internal/testingutil"
)
func TestPoll(t *gotesting.T) {
const expCalls = 5
numCalls := 0
err := testingutil.Poll(context.Background(), func(ctx context.Context) error {
numCalls++
if numCalls < expCalls {
return fmt.Errorf("intentional error #%d", numCalls)
}
return nil
}, &testingutil.PollOptions{Interval: time.Millisecond})
if err != nil {
t.Error("Poll reported error: ", err)
}
if numCalls != expCalls {
t.Errorf("Poll called func %d time(s); want %d", numCalls, expCalls)
}
}
func TestPollBreak(t *gotesting.T) {
const (
maxCalls = 5
expCalls = 3
errMsg = "break the poll"
)
numCalls := 0
mainError := errors.New("break the poll")
err := testingutil.Poll(context.Background(), func(ctx context.Context) error {
numCalls++
if numCalls == expCalls {
return testingutil.PollBreak(mainError)
}
if numCalls < maxCalls {
return fmt.Errorf("intentional error #%d", numCalls)
}
return nil
}, &testingutil.PollOptions{Interval: time.Millisecond})
if err == nil {
t.Error("Poll succeeded unintentionally")
}
if numCalls != expCalls {
t.Errorf("Poll called func %d times(s); want %d", numCalls, expCalls)
}
if err != mainError {
t.Errorf("Failed with unexpected error: got %v; want %v", err, mainError)
}
}
func TestPollCanceledContext(t *gotesting.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
numCalls := 0
err := testingutil.Poll(ctx, func(ctx context.Context) error {
numCalls++
return nil
}, nil)
if err == nil {
t.Error("Poll didn't return expected error for canceled context")
}
if numCalls != 0 {
t.Errorf("Poll called func %d time(s) for canceled context", numCalls)
}
}
func TestPollTimeout(t *gotesting.T) {
// Poll should always invoke the provided function before checking whether the timeout
// has been reached.
numCalls := 0
opts := &testingutil.PollOptions{Timeout: time.Millisecond}
err := testingutil.Poll(context.Background(), func(ctx context.Context) error {
numCalls++
<-ctx.Done()
return nil
}, opts)
if err != nil {
t.Error("Poll returned error for timeout with successful func: ", err)
}
if numCalls != 1 {
t.Errorf("Poll called func %d times; want 1", numCalls)
}
numCalls = 0
const msg = "foo"
err = testingutil.Poll(context.Background(), func(ctx context.Context) error {
numCalls++
<-ctx.Done()
return errors.New(msg)
}, opts)
if err == nil {
t.Error("Poll didn't return expected error for timeout with failing func")
} else if !strings.Contains(err.Error(), msg) {
t.Errorf("Poll returned error %q, which doesn't contain func error %q", err.Error(), msg)
}
if numCalls != 1 {
t.Errorf("Poll called func %d times; want 1", numCalls)
}
}
func TestPollTimeoutLastError(t *gotesting.T) {
opts := &testingutil.PollOptions{
Timeout: time.Minute,
Interval: time.Nanosecond,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
first := true
const msg = "this is a test error message"
if err := testingutil.Poll(ctx, func(ctx context.Context) error {
if first {
first = false
return errors.New(msg)
}
cancel()
<-ctx.Done()
return ctx.Err()
}, opts); err == nil {
t.Error("Poll didn't return expected error for timeout with failing func")
} else if !strings.Contains(err.Error(), msg) {
t.Errorf("Poll returned error %q, which doesn't contain func error %q", err.Error(), msg)
}
ctx, cancel = context.WithCancel(context.Background())
first = true
if err := testingutil.Poll(ctx, func(ctx context.Context) error {
if first {
first = false
return errors.New(msg)
}
cancel()
<-ctx.Done()
return testingutil.PollBreak(ctx.Err())
}, opts); err == nil {
t.Error("Poll didn't return expected error for timeout with failing func")
} else if !strings.Contains(err.Error(), msg) {
t.Errorf("Poll returned error %q, which doesn't contain func error %q", err.Error(), msg)
}
ctx, cancel = context.WithCancel(context.Background())
if err := testingutil.Poll(ctx, func(ctx context.Context) error {
cancel()
<-ctx.Done()
return testingutil.PollBreak(ctx.Err())
}, opts); err == nil {
t.Error("Poll didn't return expected error for timeout with failing func")
} else if err != ctx.Err() {
t.Errorf("Poll returned unexpected error: got %v; want %v", err, ctx.Err())
}
}
func TestPollUseNonContextError(t *gotesting.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Make the function return a canned error the first time and then cancel the context
// and return "context canceled" after that. Poll should return the canned error
// instead of a useless one about the context.
var msg = "foo"
numCalls := 0
err := testingutil.Poll(ctx, func(ctx context.Context) error {
numCalls++
if numCalls == 1 {
return errors.New(msg)
}
cancel()
return ctx.Err()
}, nil)
if err == nil {
t.Error("Poll didn't return expected error for canceled context")
} else if !strings.Contains(err.Error(), msg) {
t.Errorf("Poll returned error %q, which doesn't contain func error %q", err.Error(), msg)
}
}