1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
16 "git.arvados.org/arvados.git/sdk/go/arvados"
17 "git.arvados.org/arvados.git/sdk/go/arvadosclient"
18 "git.arvados.org/arvados.git/sdk/go/arvadostest"
19 "git.arvados.org/arvados.git/sdk/go/keepclient"
23 var _ = Suite(&integrationSuite{})
25 type integrationSuite struct {
27 image arvados.Collection
28 input arvados.Collection
32 cr arvados.ContainerRequest
33 client *arvados.Client
34 ac *arvadosclient.ArvadosClient
35 kc *keepclient.KeepClient
38 func (s *integrationSuite) SetUpSuite(c *C) {
39 _, err := exec.LookPath("docker")
41 c.Skip("looks like docker is not installed")
44 arvadostest.StartKeep(2, true)
46 out, err := exec.Command("docker", "load", "--input", busyboxDockerImage(c)).CombinedOutput()
49 out, err = exec.Command("arv-keepdocker", "--no-resume", "busybox:uclibc").Output()
50 imageUUID := strings.TrimSpace(string(out))
51 c.Logf("image uuid %s", imageUUID)
53 err = arvados.NewClientFromEnv().RequestAndDecode(&s.image, "GET", "arvados/v1/collections/"+imageUUID, nil, nil)
55 c.Logf("image pdh %s", s.image.PortableDataHash)
57 s.client = arvados.NewClientFromEnv()
58 s.ac, err = arvadosclient.New(s.client)
60 s.kc = keepclient.New(s.ac)
61 fs, err := s.input.FileSystem(s.client, s.kc)
63 f, err := fs.OpenFile("inputfile", os.O_CREATE|os.O_WRONLY, 0755)
65 _, err = f.Write([]byte("inputdata"))
69 s.input.ManifestText, err = fs.MarshalManifest(".")
71 err = s.client.RequestAndDecode(&s.input, "POST", "arvados/v1/collections", nil, map[string]interface{}{
72 "ensure_unique_name": true,
73 "collection": map[string]interface{}{
74 "manifest_text": s.input.ManifestText,
78 c.Logf("input pdh %s", s.input.PortableDataHash)
81 func (s *integrationSuite) TearDownSuite(c *C) {
86 err := s.client.RequestAndDecode(nil, "POST", "database/reset", nil, nil)
90 func (s *integrationSuite) SetUpTest(c *C) {
92 s.stdin = bytes.Buffer{}
93 s.stdout = bytes.Buffer{}
94 s.stderr = bytes.Buffer{}
95 s.cr = arvados.ContainerRequest{
98 OutputPath: "/mnt/out",
99 ContainerImage: s.image.PortableDataHash,
100 Mounts: map[string]arvados.Mount{
103 Content: []interface{}{
105 map[string]string{"foo": "bar"},
111 PortableDataHash: s.input.PortableDataHash,
118 RuntimeConstraints: arvados.RuntimeConstraints{
126 func (s *integrationSuite) setup(c *C) {
127 err := s.client.RequestAndDecode(&s.cr, "POST", "arvados/v1/container_requests", nil, map[string]interface{}{"container_request": map[string]interface{}{
128 "priority": s.cr.Priority,
130 "command": s.cr.Command,
131 "output_path": s.cr.OutputPath,
132 "container_image": s.cr.ContainerImage,
133 "mounts": s.cr.Mounts,
134 "runtime_constraints": s.cr.RuntimeConstraints,
135 "use_existing": false,
138 c.Assert(s.cr.ContainerUUID, Not(Equals), "")
139 err = s.client.RequestAndDecode(nil, "POST", "arvados/v1/containers/"+s.cr.ContainerUUID+"/lock", nil, nil)
143 func (s *integrationSuite) TestRunTrivialContainerWithDocker(c *C) {
145 s.testRunTrivialContainer(c)
148 func (s *integrationSuite) TestRunTrivialContainerWithSingularity(c *C) {
149 s.engine = "singularity"
150 s.testRunTrivialContainer(c)
153 func (s *integrationSuite) testRunTrivialContainer(c *C) {
154 if err := exec.Command("which", s.engine).Run(); err != nil {
155 c.Skip(fmt.Sprintf("%s: %s", s.engine, err))
157 s.cr.Command = []string{"sh", "-c", "cat /mnt/in/inputfile >/mnt/out/inputfile && cat /mnt/json >/mnt/out/json && ! touch /mnt/in/shouldbereadonly && mkdir /mnt/out/emptydir"}
159 code := command{}.RunCommand("crunch-run", []string{
160 "-runtime-engine=" + s.engine,
161 "-enable-memory-limit=false",
163 }, &s.stdin, io.MultiWriter(&s.stdout, os.Stderr), io.MultiWriter(&s.stderr, os.Stderr))
164 c.Check(code, Equals, 0)
165 err := s.client.RequestAndDecode(&s.cr, "GET", "arvados/v1/container_requests/"+s.cr.UUID, nil, nil)
167 c.Logf("Finished container request: %#v", s.cr)
169 var log arvados.Collection
170 err = s.client.RequestAndDecode(&log, "GET", "arvados/v1/collections/"+s.cr.LogUUID, nil, nil)
172 fs, err := log.FileSystem(s.client, s.kc)
174 if d, err := fs.Open("/"); c.Check(err, IsNil) {
175 fis, err := d.Readdir(-1)
177 for _, fi := range fis {
181 f, err := fs.Open(fi.Name())
183 buf, err := ioutil.ReadAll(f)
185 c.Logf("\n===== %s =====\n%s", fi.Name(), buf)
189 var output arvados.Collection
190 err = s.client.RequestAndDecode(&output, "GET", "arvados/v1/collections/"+s.cr.OutputUUID, nil, nil)
192 fs, err = output.FileSystem(s.client, s.kc)
194 if f, err := fs.Open("inputfile"); c.Check(err, IsNil) {
196 buf, err := ioutil.ReadAll(f)
198 c.Check(string(buf), Equals, "inputdata")
200 if f, err := fs.Open("json"); c.Check(err, IsNil) {
202 buf, err := ioutil.ReadAll(f)
204 c.Check(string(buf), Equals, `["foo",{"foo":"bar"},null]`)
206 if fi, err := fs.Stat("emptydir"); c.Check(err, IsNil) {
207 c.Check(fi.IsDir(), Equals, true)
209 if d, err := fs.Open("emptydir"); c.Check(err, IsNil) {
211 fis, err := d.Readdir(-1)
213 // crunch-run still saves a ".keep" file to preserve
214 // empty dirs even though that shouldn't be
215 // necessary. Ideally we would do:
216 // c.Check(fis, HasLen, 0)
217 for _, fi := range fis {
218 c.Check(fi.Name(), Equals, ".keep")