[ARVADOS] updated: c071433ab8d50a2fa92d1f75babf5a4ec9f0f5a8
Git user
git at public.curoverse.com
Wed Mar 22 16:50:55 EDT 2017
Summary of changes:
services/crunch-run/crunchrun.go | 69 ++++++++++++++---
services/crunch-run/crunchrun_test.go | 141 ++++++++++++++++------------------
2 files changed, 124 insertions(+), 86 deletions(-)
via c071433ab8d50a2fa92d1f75babf5a4ec9f0f5a8 (commit)
from a8b6688f3613b36204d0d38a241fd154968b2571 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit c071433ab8d50a2fa92d1f75babf5a4ec9f0f5a8
Author: radhika <radhika at curoverse.com>
Date: Wed Mar 22 16:47:44 2017 -0400
9132: Use ThinDockerClientProxy to overcome the import issue around "github.com/docker/docker/vendor/golang.org/x/net/context".
Perform most of the test updates needed to use the new API.
diff --git a/services/crunch-run/crunchrun.go b/services/crunch-run/crunchrun.go
index 628cfd0..49f34d3 100644
--- a/services/crunch-run/crunchrun.go
+++ b/services/crunch-run/crunchrun.go
@@ -59,15 +59,62 @@ type MkTempDir func(string, string) (string, error)
// ThinDockerClient is the minimal Docker client interface used by crunch-run.
type ThinDockerClient interface {
- ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error)
- ImageLoad(ctx context.Context, input io.Reader, quiet bool) (dockertypes.ImageLoadResponse, error)
- ImageRemove(ctx context.Context, image string, options dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error)
+ ContainerAttach(ctx context.Context, container string, options dockertypes.ContainerAttachOptions) (dockertypes.HijackedResponse, error)
ContainerCreate(ctx context.Context, config *dockercontainer.Config, hostConfig *dockercontainer.HostConfig,
networkingConfig *dockernetwork.NetworkingConfig, containerName string) (dockercontainer.ContainerCreateCreatedBody, error)
ContainerStart(ctx context.Context, container string, options dockertypes.ContainerStartOptions) error
- ContainerAttach(ctx context.Context, container string, options dockertypes.ContainerAttachOptions) (dockertypes.HijackedResponse, error)
ContainerStop(ctx context.Context, container string, timeout *time.Duration) error
ContainerWait(ctx context.Context, container string) (int64, error)
+ ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error)
+ ImageLoad(ctx context.Context, input io.Reader, quiet bool) (dockertypes.ImageLoadResponse, error)
+ ImageRemove(ctx context.Context, image string, options dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error)
+}
+
+// ThinDockerClientProxy is a proxy implementation of ThinDockerClient
+// that executes the docker requests on dockerclient.Client
+type ThinDockerClientProxy struct {
+ Docker *dockerclient.Client
+}
+
+// ContainerAttach invokes dockerclient.Client.ContainerAttach
+func (proxy ThinDockerClientProxy) ContainerAttach(ctx context.Context, container string, options dockertypes.ContainerAttachOptions) (dockertypes.HijackedResponse, error) {
+ return proxy.Docker.ContainerAttach(ctx, container, options)
+}
+
+// ContainerCreate invokes dockerclient.Client.ContainerCreate
+func (proxy ThinDockerClientProxy) ContainerCreate(ctx context.Context, config *dockercontainer.Config, hostConfig *dockercontainer.HostConfig,
+ networkingConfig *dockernetwork.NetworkingConfig, containerName string) (dockercontainer.ContainerCreateCreatedBody, error) {
+ return proxy.Docker.ContainerCreate(ctx, config, hostConfig, networkingConfig, containerName)
+}
+
+// ContainerStart invokes dockerclient.Client.ContainerStart
+func (proxy ThinDockerClientProxy) ContainerStart(ctx context.Context, container string, options dockertypes.ContainerStartOptions) error {
+ return proxy.Docker.ContainerStart(ctx, container, options)
+}
+
+// ContainerStop invokes dockerclient.Client.ContainerStop
+func (proxy ThinDockerClientProxy) ContainerStop(ctx context.Context, container string, timeout *time.Duration) error {
+ return proxy.Docker.ContainerStop(ctx, container, timeout)
+}
+
+// ContainerWait invokes dockerclient.Client.ContainerWait
+func (proxy ThinDockerClientProxy) ContainerWait(ctx context.Context, container string) (int64, error) {
+ return proxy.Docker.ContainerWait(ctx, container)
+}
+
+// ImageInspectWithRaw invokes dockerclient.Client.ImageInspectWithRaw
+func (proxy ThinDockerClientProxy) ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error) {
+ return proxy.Docker.ImageInspectWithRaw(ctx, image)
+}
+
+// ImageLoad invokes dockerclient.Client.ImageLoad
+func (proxy ThinDockerClientProxy) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (dockertypes.ImageLoadResponse, error) {
+ return proxy.Docker.ImageLoad(ctx, input, quiet)
+}
+
+// ImageRemove invokes dockerclient.Client.ImageRemove
+func (proxy ThinDockerClientProxy) ImageRemove(ctx context.Context, image string, options dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error) {
+ return proxy.Docker.ImageRemove(ctx, image, options)
}
// ContainerRunner is the main stateful struct used for a single execution of a
@@ -189,10 +236,10 @@ func (runner *ContainerRunner) LoadImage() (err error) {
}
response, err := runner.Docker.ImageLoad(context.TODO(), readCloser, false)
- response.Body.Close()
if err != nil {
return fmt.Errorf("While loading container image into Docker: %v", err)
}
+ response.Body.Close()
} else {
runner.CrunchLog.Print("Docker image is available")
}
@@ -622,11 +669,9 @@ func (runner *ContainerRunner) WaitFinish() error {
return fmt.Errorf("container wait: %v", err)
}
- if waitDocker != 0 { // what is the acceptable waitDocker code?
- runner.CrunchLog.Printf("container wait API status code: %v", waitDocker)
- code := int(waitDocker)
- runner.ExitCode = &code
- }
+ runner.CrunchLog.Printf("container wait API status code: %v", waitDocker)
+ code := int(waitDocker)
+ runner.ExitCode = &code
waitMount := runner.ArvMountExit
select {
@@ -1074,7 +1119,9 @@ func main() {
log.Fatalf("%s: %v", containerId, err)
}
- cr := NewContainerRunner(api, kc, docker, containerId)
+ dockerClientProxy := ThinDockerClientProxy{Docker: docker}
+
+ cr := NewContainerRunner(api, kc, dockerClientProxy, containerId)
cr.statInterval = *statInterval
cr.cgroupRoot = *cgroupRoot
cr.expectCgroupParent = *cgroupParent
diff --git a/services/crunch-run/crunchrun_test.go b/services/crunch-run/crunchrun_test.go
index eaf62d1..b1f2228 100644
--- a/services/crunch-run/crunchrun_test.go
+++ b/services/crunch-run/crunchrun_test.go
@@ -1,7 +1,9 @@
package main
import (
+ "bufio"
"bytes"
+ "context"
"crypto/md5"
"encoding/json"
"errors"
@@ -22,7 +24,10 @@ import (
"git.curoverse.com/arvados.git/sdk/go/arvadosclient"
"git.curoverse.com/arvados.git/sdk/go/keepclient"
"git.curoverse.com/arvados.git/sdk/go/manifest"
- "github.com/curoverse/dockerclient"
+
+ dockertypes "github.com/docker/docker/api/types"
+ dockercontainer "github.com/docker/docker/api/types/container"
+ dockernetwork "github.com/docker/docker/api/types/network"
. "gopkg.in/check.v1"
)
@@ -72,55 +77,36 @@ type TestDockerClient struct {
logReader io.ReadCloser
logWriter io.WriteCloser
fn func(t *TestDockerClient)
- finish chan dockerclient.WaitResult
+ finish int
stop chan bool
cwd string
env []string
api *ArvTestClient
}
-func NewTestDockerClient() *TestDockerClient {
+func NewTestDockerClient(exitCode int) *TestDockerClient {
t := &TestDockerClient{}
t.logReader, t.logWriter = io.Pipe()
- t.finish = make(chan dockerclient.WaitResult)
+ t.finish = exitCode
t.stop = make(chan bool)
t.cwd = "/"
return t
}
-func (t *TestDockerClient) StopContainer(id string, timeout int) error {
- t.stop <- true
- return nil
-}
-
-func (t *TestDockerClient) InspectImage(id string) (*dockerclient.ImageInfo, error) {
- if t.imageLoaded == id {
- return &dockerclient.ImageInfo{}, nil
- } else {
- return nil, errors.New("")
- }
-}
-
-func (t *TestDockerClient) LoadImage(reader io.Reader) error {
- _, err := io.Copy(ioutil.Discard, reader)
- if err != nil {
- return err
- } else {
- t.imageLoaded = hwImageId
- return nil
- }
+func (t *TestDockerClient) ContainerAttach(ctx context.Context, container string, options dockertypes.ContainerAttachOptions) (dockertypes.HijackedResponse, error) {
+ return dockertypes.HijackedResponse{Reader: bufio.NewReader(t.logReader)}, nil
}
-func (t *TestDockerClient) CreateContainer(config *dockerclient.ContainerConfig, name string, authConfig *dockerclient.AuthConfig) (string, error) {
+func (t *TestDockerClient) ContainerCreate(ctx context.Context, config *dockercontainer.Config, hostConfig *dockercontainer.HostConfig, networkingConfig *dockernetwork.NetworkingConfig, containerName string) (dockercontainer.ContainerCreateCreatedBody, error) {
if config.WorkingDir != "" {
t.cwd = config.WorkingDir
}
t.env = config.Env
- return "abcde", nil
+ return dockercontainer.ContainerCreateCreatedBody{ID: "abcde"}, nil
}
-func (t *TestDockerClient) StartContainer(id string, config *dockerclient.HostConfig) error {
- if id == "abcde" {
+func (t *TestDockerClient) ContainerStart(ctx context.Context, container string, options dockertypes.ContainerStartOptions) error {
+ if container == "abcde" {
go t.fn(t)
return nil
} else {
@@ -128,15 +114,34 @@ func (t *TestDockerClient) StartContainer(id string, config *dockerclient.HostCo
}
}
-func (t *TestDockerClient) AttachContainer(id string, options *dockerclient.AttachOptions) (io.ReadCloser, error) {
- return t.logReader, nil
+func (t *TestDockerClient) ContainerStop(ctx context.Context, container string, timeout *time.Duration) error {
+ t.stop <- true
+ return nil
}
-func (t *TestDockerClient) Wait(id string) <-chan dockerclient.WaitResult {
- return t.finish
+func (t *TestDockerClient) ContainerWait(ctx context.Context, container string) (int64, error) {
+ return int64(t.finish), nil
+}
+
+func (t *TestDockerClient) ImageInspectWithRaw(ctx context.Context, image string) (dockertypes.ImageInspect, []byte, error) {
+ if t.imageLoaded == image {
+ return dockertypes.ImageInspect{}, nil, nil
+ } else {
+ return dockertypes.ImageInspect{}, nil, errors.New("")
+ }
+}
+
+func (t *TestDockerClient) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (dockertypes.ImageLoadResponse, error) {
+ _, err := io.Copy(ioutil.Discard, input)
+ if err != nil {
+ return dockertypes.ImageLoadResponse{}, err
+ } else {
+ t.imageLoaded = hwImageId
+ return dockertypes.ImageLoadResponse{Body: ioutil.NopCloser(input)}, nil
+ }
}
-func (*TestDockerClient) RemoveImage(name string, force bool) ([]*dockerclient.ImageDelete, error) {
+func (*TestDockerClient) ImageRemove(ctx context.Context, image string, options dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDeleteResponseItem, error) {
return nil, nil
}
@@ -271,12 +276,12 @@ func (client *KeepTestClient) ManifestFileReader(m manifest.Manifest, filename s
func (s *TestSuite) TestLoadImage(c *C) {
kc := &KeepTestClient{}
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
cr := NewContainerRunner(&ArvTestClient{}, kc, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
- _, err := cr.Docker.RemoveImage(hwImageId, true)
+ _, err := cr.Docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{})
- _, err = cr.Docker.InspectImage(hwImageId)
+ _, _, err = cr.Docker.ImageInspectWithRaw(nil, hwImageId)
c.Check(err, NotNil)
cr.Container.ContainerImage = hwPDH
@@ -289,13 +294,13 @@ func (s *TestSuite) TestLoadImage(c *C) {
c.Check(err, IsNil)
defer func() {
- cr.Docker.RemoveImage(hwImageId, true)
+ cr.Docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{})
}()
c.Check(kc.Called, Equals, true)
c.Check(cr.ContainerConfig.Image, Equals, hwImageId)
- _, err = cr.Docker.InspectImage(hwImageId)
+ _, _, err = cr.Docker.ImageInspectWithRaw(nil, hwImageId)
c.Check(err, IsNil)
// (2) Test using image that's already loaded
@@ -382,7 +387,7 @@ func (s *TestSuite) TestLoadImageArvError(c *C) {
func (s *TestSuite) TestLoadImageKeepError(c *C) {
// (2) Keep error
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
cr := NewContainerRunner(&ArvTestClient{}, KeepErrorTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
cr.Container.ContainerImage = hwPDH
@@ -401,7 +406,7 @@ func (s *TestSuite) TestLoadImageCollectionError(c *C) {
func (s *TestSuite) TestLoadImageKeepReadError(c *C) {
// (4) Collection doesn't contain image
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
cr := NewContainerRunner(&ArvTestClient{}, KeepReadErrorTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
cr.Container.ContainerImage = hwPDH
@@ -442,11 +447,10 @@ func dockerLog(fd byte, msg string) []byte {
}
func (s *TestSuite) TestRunContainer(c *C) {
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
docker.fn = func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, "Hello world\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{}
}
cr := NewContainerRunner(&ArvTestClient{}, &KeepTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
@@ -537,14 +541,14 @@ func (s *TestSuite) TestUpdateContainerCancelled(c *C) {
// Used by the TestFullRun*() test below to DRY up boilerplate setup to do full
// dress rehearsal of the Run() function, starting from a JSON container record.
-func FullRunHelper(c *C, record string, extraMounts []string, fn func(t *TestDockerClient)) (api *ArvTestClient, cr *ContainerRunner, realTemp string) {
+func FullRunHelper(c *C, record string, extraMounts []string, exitCode int, fn func(t *TestDockerClient)) (api *ArvTestClient, cr *ContainerRunner, realTemp string) {
rec := arvados.Container{}
err := json.Unmarshal([]byte(record), &rec)
c.Check(err, IsNil)
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(exitCode)
docker.fn = fn
- docker.RemoveImage(hwImageId, true)
+ docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{})
api = &ArvTestClient{Container: rec}
docker.api = api
@@ -604,10 +608,9 @@ func (s *TestSuite) TestFullRunHello(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, "hello world\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -626,10 +629,9 @@ func (s *TestSuite) TestCrunchstat(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
- }`, nil, func(t *TestDockerClient) {
+ }`, nil, 0, func(t *TestDockerClient) {
time.Sleep(time.Second)
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -659,11 +661,10 @@ func (s *TestSuite) TestFullRunStderr(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 1, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, "hello\n"))
t.logWriter.Write(dockerLog(2, "world\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 1}
})
final := api.CalledWith("container.state", "Complete")
@@ -685,10 +686,9 @@ func (s *TestSuite) TestFullRunDefaultCwd(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.cwd+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -707,10 +707,9 @@ func (s *TestSuite) TestFullRunSetCwd(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.cwd+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -755,14 +754,13 @@ func (s *TestSuite) testStopContainer(c *C, setup func(cr *ContainerRunner)) {
err := json.Unmarshal([]byte(record), &rec)
c.Check(err, IsNil)
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
docker.fn = func(t *TestDockerClient) {
<-t.stop
t.logWriter.Write(dockerLog(1, "foo\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
}
- docker.RemoveImage(hwImageId, true)
+ docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{})
api := &ArvTestClient{Container: rec}
cr := NewContainerRunner(api, &KeepTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
@@ -799,10 +797,9 @@ func (s *TestSuite) TestFullRunSetEnv(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[0][7:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -1057,10 +1054,9 @@ func (s *TestSuite) TestStdout(c *C) {
"runtime_constraints": {}
}`
- api, _, _ := FullRunHelper(c, helperRecord, nil, func(t *TestDockerClient) {
+ api, _, _ := FullRunHelper(c, helperRecord, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[0][7:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -1074,9 +1070,9 @@ func StdoutErrorRunHelper(c *C, record string, fn func(t *TestDockerClient)) (ap
err = json.Unmarshal([]byte(record), &rec)
c.Check(err, IsNil)
- docker := NewTestDockerClient()
+ docker := NewTestDockerClient(0)
docker.fn = fn
- docker.RemoveImage(hwImageId, true)
+ docker.ImageRemove(nil, hwImageId, dockertypes.ImageRemoveOptions{})
api = &ArvTestClient{Container: rec}
cr = NewContainerRunner(api, &KeepTestClient{}, docker, "zzzzz-zzzzz-zzzzzzzzzzzzzzz")
@@ -1129,10 +1125,9 @@ func (s *TestSuite) TestFullRunWithAPI(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {"API": true}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[1][17:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -1153,10 +1148,9 @@ func (s *TestSuite) TestFullRunSetOutput(c *C) {
"output_path": "/tmp",
"priority": 1,
"runtime_constraints": {"API": true}
-}`, nil, func(t *TestDockerClient) {
+}`, nil, 0, func(t *TestDockerClient) {
t.api.Container.Output = "d4ab34d3d4f8a72f5c4973051ae69fab+122"
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -1185,10 +1179,9 @@ func (s *TestSuite) TestStdoutWithExcludeFromOutputMountPointUnderOutputDir(c *C
extraMounts := []string{"a3e8f74c6f101eae01fa08bfb4e49b3a+54"}
- api, _, _ := FullRunHelper(c, helperRecord, extraMounts, func(t *TestDockerClient) {
+ api, _, _ := FullRunHelper(c, helperRecord, extraMounts, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[0][7:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
@@ -1221,10 +1214,9 @@ func (s *TestSuite) TestStdoutWithMultipleMountPointsUnderOutputDir(c *C) {
"a0def87f80dd594d4675809e83bd4f15+367/subdir1/subdir2/file2_in_subdir2.txt",
}
- api, runner, realtemp := FullRunHelper(c, helperRecord, extraMounts, func(t *TestDockerClient) {
+ api, runner, realtemp := FullRunHelper(c, helperRecord, extraMounts, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[0][7:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(runner.Binds, DeepEquals, []string{realtemp + "/2:/tmp",
@@ -1273,10 +1265,9 @@ func (s *TestSuite) TestStdoutWithMountPointsUnderOutputDirDenormalizedManifest(
"b0def87f80dd594d4675809e83bd4f15+367/subdir1/file2_in_subdir1.txt",
}
- api, _, _ := FullRunHelper(c, helperRecord, extraMounts, func(t *TestDockerClient) {
+ api, _, _ := FullRunHelper(c, helperRecord, extraMounts, 0, func(t *TestDockerClient) {
t.logWriter.Write(dockerLog(1, t.env[0][7:]+"\n"))
t.logWriter.Close()
- t.finish <- dockerclient.WaitResult{ExitCode: 0}
})
c.Check(api.CalledWith("container.exit_code", 0), NotNil)
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list