1// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package testutil provides test utility functions.
16package testutil
17
18import (
19	"net/url"
20	"runtime"
21	"testing"
22	"time"
23)
24
25// WaitSchedule briefly sleeps in order to invoke the go scheduler.
26// TODO: improve this when we are able to know the schedule or status of target go-routine.
27func WaitSchedule() {
28	time.Sleep(10 * time.Millisecond)
29}
30
31func MustNewURLs(t *testing.T, urls []string) []url.URL {
32	if urls == nil {
33		return nil
34	}
35	var us []url.URL
36	for _, url := range urls {
37		u := MustNewURL(t, url)
38		us = append(us, *u)
39	}
40	return us
41}
42
43func MustNewURL(t *testing.T, s string) *url.URL {
44	u, err := url.Parse(s)
45	if err != nil {
46		t.Fatalf("parse %v error: %v", s, err)
47	}
48	return u
49}
50
51// FatalStack helps to fatal the test and print out the stacks of all running goroutines.
52func FatalStack(t *testing.T, s string) {
53	stackTrace := make([]byte, 1024*1024)
54	n := runtime.Stack(stackTrace, true)
55	t.Error(string(stackTrace[:n]))
56	t.Fatalf(s)
57}
58
59// ConditionFunc returns true when a condition is met.
60type ConditionFunc func() (bool, error)
61
62// Poll calls a condition function repeatedly on a polling interval until it returns true, returns an error
63// or the timeout is reached. If the condition function returns true or an error before the timeout, Poll
64// immediately returns with the true value or the error. If the timeout is exceeded, Poll returns false.
65func Poll(interval time.Duration, timeout time.Duration, condition ConditionFunc) (bool, error) {
66	timeoutCh := time.After(timeout)
67	ticker := time.NewTicker(interval)
68	defer ticker.Stop()
69
70	for {
71		select {
72		case <-timeoutCh:
73			return false, nil
74		case <-ticker.C:
75			success, err := condition()
76			if err != nil {
77				return false, err
78			}
79			if success {
80				return true, nil
81			}
82		}
83	}
84}
85