func waitForSubstring(fn func() string, substr string, timeout time.Duration) error {
	var s string
	found := make(chan struct{})
	var exit int32
	go func() {
		for atomic.LoadInt32(&exit) == 0 {
			s = fn()
			if strings.Contains(s, substr) {
				found <- struct{}{}
				return
			}
			time.Sleep(timeout / 100)
		}
	}()
	select {
	case <-found:
		return nil
	case <-time.After(timeout):
		atomic.StoreInt32(&exit, 1)
	}
	return fmt.Errorf("%q does not contain %q", s, substr)
}
------------------------------------------------------------------------------
Replaces ginkgo's Eventually.
package redis_test
import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync/atomic"
	"syscall"
	"testing"
	"time"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"gopkg.in/redis.v3"
)
const (
	redisPort          = "6380"
	redisAddr          = ":" + redisPort
	redisSecondaryPort = "6381"
)
const (
	ringShard1Port = "6390"
	ringShard2Port = "6391"
)
const (
	sentinelName       = "mymaster"
	sentinelMasterPort = "8123"
	sentinelSlave1Port = "8124"
	sentinelSlave2Port = "8125"
	sentinelPort       = "8126"
)
var (
	redisMain                                                *redisProcess
	ringShard1, ringShard2                                   *redisProcess
	sentinelMaster, sentinelSlave1, sentinelSlave2, sentinel *redisProcess
)
var cluster = &clusterScenario{
	ports:     []string{"8220", "8221", "8222", "8223", "8224", "8225"},
	nodeIds:   make([]string, 6),
	processes: make(map[string]*redisProcess, 6),
	clients:   make(map[string]*redis.Client, 6),
}
var _ = BeforeSuite(func() {
	var err error
	redisMain, err = startRedis(redisPort)
	Expect(err).NotTo(HaveOccurred())
	ringShard1, err = startRedis(ringShard1Port)
	Expect(err).NotTo(HaveOccurred())
	ringShard2, err = startRedis(ringShard2Port)
	Expect(err).NotTo(HaveOccurred())
	sentinelMaster, err = startRedis(sentinelMasterPort)
	Expect(err).NotTo(HaveOccurred())
	sentinel, err = startSentinel(sentinelPort, sentinelName, sentinelMasterPort)
	Expect(err).NotTo(HaveOccurred())
	sentinelSlave1, err = startRedis(
		sentinelSlave1Port, "--slaveof", "127.0.0.1", sentinelMasterPort)
	Expect(err).NotTo(HaveOccurred())
	sentinelSlave2, err = startRedis(
		sentinelSlave2Port, "--slaveof", "127.0.0.1", sentinelMasterPort)
	Expect(err).NotTo(HaveOccurred())
	Expect(startCluster(cluster)).NotTo(HaveOccurred())
})
var _ = AfterSuite(func() {
	Expect(redisMain.Close()).NotTo(HaveOccurred())
	Expect(ringShard1.Close()).NotTo(HaveOccurred())
	Expect(ringShard2.Close()).NotTo(HaveOccurred())
	Expect(sentinel.Close()).NotTo(HaveOccurred())
	Expect(sentinelSlave1.Close()).NotTo(HaveOccurred())
	Expect(sentinelSlave2.Close()).NotTo(HaveOccurred())
	Expect(sentinelMaster.Close()).NotTo(HaveOccurred())
	Expect(stopCluster(cluster)).NotTo(HaveOccurred())
})
func TestGinkgoSuite(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "gopkg.in/redis.v3")
}