1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/hack/integration-cli-on-swarm/agent/master/call.go
Akihiro Suda 28797019b3 [EXPERIMENTAL] Integration Test on Swarm
This commit adds contrib/integration-cli-on-swarm/integration-cli-on-swarm.sh,
which enables IT to be running in parallel, using Swarm-mode and Funker.

Please refer to contrib/integration-cli-on-swarm/README.md

The test takes almost 5 to 6 minutes, with 10 n1-standard-4 GCE instances.

  $ ./contrib/integration-cli-on-swarm/integration-cli-on-swarm.sh --push-worker-image example.gcr.io/foo/bar --replicas 30 --shuffle
  2016/12/29 08:32:15 Loaded 1618 tests (30 chunks)
  2016/12/29 08:32:15 Executing 30 chunks in parallel, against "integration-cli-worker"
  2016/12/29 08:32:15 Executing chunk 0 (contains 54 test filters)
  ..
  2016/12/29 08:34:34 Finished chunk 28 [1/30] with 54 test filters in 2m19.098068003s, code=0.
  2016/12/29 08:34:38 Finished chunk 12 [2/30] with 54 test filters in 2m23.088569511s, code=0.
  2016/12/29 08:34:48 Finished chunk 10 [3/30] with 54 test filters in 2m33.880679079s, code=0.
  2016/12/29 08:34:54 Finished chunk 20 [4/30] with 54 test filters in 2m39.973747028s, code=0.
  2016/12/29 08:35:11 Finished chunk 18 [5/30] with 54 test filters in 2m56.28384361s, code=0.
  2016/12/29 08:35:11 Finished chunk 29 [6/30] with 52 test filters in 2m56.54047088s, code=0.
  2016/12/29 08:35:15 Finished chunk 1 [7/30] with 54 test filters in 3m0.285044426s, code=0.
  2016/12/29 08:35:22 Finished chunk 6 [8/30] with 54 test filters in 3m7.211775338s, code=0.
  2016/12/29 08:35:24 Finished chunk 25 [9/30] with 54 test filters in 3m9.938413009s, code=0.
  2016/12/29 08:35:30 Finished chunk 27 [10/30] with 54 test filters in 3m15.219834368s, code=0.
  2016/12/29 08:35:36 Finished chunk 9 [11/30] with 54 test filters in 3m21.615434162s, code=0.
  2016/12/29 08:35:41 Finished chunk 13 [12/30] with 54 test filters in 3m26.576907401s, code=0.
  2016/12/29 08:35:45 Finished chunk 17 [13/30] with 54 test filters in 3m30.290752537s, code=0.
  2016/12/29 08:35:53 Finished chunk 2 [14/30] with 54 test filters in 3m38.148423321s, code=0.
  2016/12/29 08:35:55 Finished chunk 24 [15/30] with 54 test filters in 3m40.09669137s, code=0.
  2016/12/29 08:35:57 Finished chunk 8 [16/30] with 54 test filters in 3m42.299945108s, code=0.
  2016/12/29 08:35:57 Finished chunk 22 [17/30] with 54 test filters in 3m42.946558809s, code=0.
  2016/12/29 08:35:59 Finished chunk 23 [18/30] with 54 test filters in 3m44.232557165s, code=0.
  2016/12/29 08:36:02 Finished chunk 3 [19/30] with 54 test filters in 3m47.112051358s, code=0.
  2016/12/29 08:36:11 Finished chunk 15 [20/30] with 54 test filters in 3m56.340656645s, code=0.
  2016/12/29 08:36:11 Finished chunk 11 [21/30] with 54 test filters in 3m56.882401231s, code=0.
  2016/12/29 08:36:22 Finished chunk 19 [22/30] with 54 test filters in 4m7.551093516s, code=0.
  2016/12/29 08:36:23 Finished chunk 21 [23/30] with 54 test filters in 4m8.221093446s, code=0.
  2016/12/29 08:36:25 Finished chunk 16 [24/30] with 54 test filters in 4m10.450451705s, code=0.
  2016/12/29 08:36:27 Finished chunk 5 [25/30] with 54 test filters in 4m12.162272692s, code=0.
  2016/12/29 08:36:28 Finished chunk 14 [26/30] with 54 test filters in 4m13.977801031s, code=0.
  2016/12/29 08:36:29 Finished chunk 0 [27/30] with 54 test filters in 4m14.34086812s, code=0.
  2016/12/29 08:36:49 Finished chunk 26 [28/30] with 54 test filters in 4m34.437085539s, code=0.
  2016/12/29 08:37:14 Finished chunk 7 [29/30] with 54 test filters in 4m59.22902721s, code=0.
  2016/12/29 08:37:20 Finished chunk 4 [30/30] with 54 test filters in 5m5.103469214s, code=0.
  2016/12/29 08:37:20 Executed 30 chunks in 5m5.104379119s. PASS: 30, FAIL: 0.

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
2017-02-28 02:10:09 +00:00

132 lines
3.8 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/bfirsh/funker-go"
"github.com/docker/docker/hack/integration-cli-on-swarm/agent/types"
)
const (
// funkerRetryTimeout is for the issue https://github.com/bfirsh/funker/issues/3
// When all the funker replicas are busy in their own job, we cannot connect to funker.
funkerRetryTimeout = 1 * time.Hour
funkerRetryDuration = 1 * time.Second
)
// ticker is needed for some CI (e.g., on Travis, job is aborted when no output emitted for 10 minutes)
func ticker(d time.Duration) chan struct{} {
t := time.NewTicker(d)
stop := make(chan struct{})
go func() {
for {
select {
case <-t.C:
log.Printf("tick (just for keeping CI job active) per %s", d.String())
case <-stop:
t.Stop()
}
}
}()
return stop
}
func executeTests(funkerName string, testChunks [][]string) error {
tickerStopper := ticker(9*time.Minute + 55*time.Second)
defer func() {
close(tickerStopper)
}()
begin := time.Now()
log.Printf("Executing %d chunks in parallel, against %q", len(testChunks), funkerName)
var wg sync.WaitGroup
var passed, failed uint32
for chunkID, tests := range testChunks {
log.Printf("Executing chunk %d (contains %d test filters)", chunkID, len(tests))
wg.Add(1)
go func(chunkID int, tests []string) {
defer wg.Done()
chunkBegin := time.Now()
result, err := executeTestChunkWithRetry(funkerName, types.Args{
ChunkID: chunkID,
Tests: tests,
})
if result.RawLog != "" {
for _, s := range strings.Split(result.RawLog, "\n") {
log.Printf("Log (chunk %d): %s", chunkID, s)
}
}
if err != nil {
log.Printf("Error while executing chunk %d: %v",
chunkID, err)
atomic.AddUint32(&failed, 1)
} else {
if result.Code == 0 {
atomic.AddUint32(&passed, 1)
} else {
atomic.AddUint32(&failed, 1)
}
log.Printf("Finished chunk %d [%d/%d] with %d test filters in %s, code=%d.",
chunkID, passed+failed, len(testChunks), len(tests),
time.Now().Sub(chunkBegin), result.Code)
}
}(chunkID, tests)
}
wg.Wait()
// TODO: print actual tests rather than chunks
log.Printf("Executed %d chunks in %s. PASS: %d, FAIL: %d.",
len(testChunks), time.Now().Sub(begin), passed, failed)
if failed > 0 {
return fmt.Errorf("%d chunks failed", failed)
}
return nil
}
func executeTestChunk(funkerName string, args types.Args) (types.Result, error) {
ret, err := funker.Call(funkerName, args)
if err != nil {
return types.Result{}, err
}
tmp, err := json.Marshal(ret)
if err != nil {
return types.Result{}, err
}
var result types.Result
err = json.Unmarshal(tmp, &result)
return result, err
}
func executeTestChunkWithRetry(funkerName string, args types.Args) (types.Result, error) {
begin := time.Now()
for i := 0; time.Now().Sub(begin) < funkerRetryTimeout; i++ {
result, err := executeTestChunk(funkerName, args)
if err == nil {
log.Printf("executeTestChunk(%q, %d) returned code %d in trial %d", funkerName, args.ChunkID, result.Code, i)
return result, nil
}
if errorSeemsInteresting(err) {
log.Printf("Error while calling executeTestChunk(%q, %d), will retry (trial %d): %v",
funkerName, args.ChunkID, i, err)
}
// TODO: non-constant sleep
time.Sleep(funkerRetryDuration)
}
return types.Result{}, fmt.Errorf("could not call executeTestChunk(%q, %d) in %v", funkerName, args.ChunkID, funkerRetryTimeout)
}
// errorSeemsInteresting returns true if err does not seem about https://github.com/bfirsh/funker/issues/3
func errorSeemsInteresting(err error) bool {
boringSubstrs := []string{"connection refused", "connection reset by peer", "no such host", "transport endpoint is not connected", "no route to host"}
errS := err.Error()
for _, boringS := range boringSubstrs {
if strings.Contains(errS, boringS) {
return false
}
}
return true
}