Example #1
0
func (s *GardenServer) reapContainer(container garden.Container) {
	s.logger.Info("reaping", lager.Data{
		"handle":     container.Handle(),
		"grace-time": s.backend.GraceTime(container).String(),
	})

	s.backend.Destroy(container.Handle())
}
Example #2
0
func (exchanger exchanger) Info(logger lager.Logger, gardenContainer garden.Container) (executor.Container, error) {
	logger = logger.Session("info", lager.Data{"handle": gardenContainer.Handle()})

	logger.Debug("getting-info")
	info, err := gardenContainer.Info()
	if err != nil {
		logger.Error("failed-getting-info", err)
		return executor.Container{}, err
	}
	logger.Debug("succeeded-getting-info")

	return garden2executor(gardenContainer.Handle(), info)
}
			}, ","),
			"-allowNetworks", allowedListenerIP+"/32",
		)

		// check that the IPs were preserved over restart
		Expect(containerIP(blockedListener)).To(Equal(blockedListenerIP))
		Expect(containerIP(unblockedListener)).To(Equal(unblockedListenerIP))
		Expect(containerIP(allowedListener)).To(Equal(allowedListenerIP))

		// create a container with the new deny network configuration
		sender, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		err := client.Destroy(sender.Handle())
		Expect(err).ToNot(HaveOccurred())

		err = client.Destroy(blockedListener.Handle())
		Expect(err).ToNot(HaveOccurred())

		err = client.Destroy(unblockedListener.Handle())
		Expect(err).ToNot(HaveOccurred())

		err = client.Destroy(allowedListener.Handle())
		Expect(err).ToNot(HaveOccurred())
	})

	runInContainer := func(container garden.Container, script string) garden.Process {
		process, err := container.Run(garden.ProcessSpec{
			User: "******",
Example #4
0
				}
				process, err := os.FindProcess(pingProcess.Pid())
				if err == nil {
					process.Kill()
				}
			})

			It("is not allowed", func() {
				// TODO: make the executable name unique so to avoid test pollution
				_, err := container.Run(garden.ProcessSpec{
					Path: "bin/JobBreakoutTest.exe",
					Args: []string{"ping 192.0.2.2 -n 1 -w 10000"},
				}, garden.ProcessIO{})
				Expect(err).ShouldNot(HaveOccurred())

				err = client.Destroy(container.Handle())
				Expect(err).ShouldNot(HaveOccurred())

				processes, err := ps.Processes()
				Expect(err).ShouldNot(HaveOccurred())
				for _, proc := range processes {
					fmt.Println(proc.Executable())
					if proc.Executable() == "PING.EXE" {
						pingProcess = proc
						Expect(proc.Executable()).NotTo(Equal("PING.EXE"))
					}
				}
			})
		})

	})
							}, garden.ProcessIO{
								Stdout: byteCounter,
							})
							Expect(err).ToNot(HaveOccurred())

							spawned <- true
						}()
					}

					for j := 0; j < numToSpawn; j++ {
						<-spawned
					}
				})

				AfterEach(func() {
					err := client.Destroy(container.Handle())
					Expect(err).ToNot(HaveOccurred())
				})

				Measure("it should not adversely affect the rest of the API", func(b Benchmarker) {
					var newContainer garden.Container

					b.Time("creating another container", func() {
						var err error

						newContainer, err = client.Create(garden.ContainerSpec{})
						Expect(err).ToNot(HaveOccurred())
					})

					for i := 0; i < repeats; i++ {
						b.Time("getting container info ("+strconv.Itoa(repeats)+"x)", func() {
Example #6
0
			)

			BeforeEach(func() {
				var err error
				container, err = gdnr.Lookup("banana")
				Expect(err).NotTo(HaveOccurred())
			})

			It("asks the netwoker to forward the correct ports", func() {
				_, _, err := container.NetIn(externalPort, contianerPort)

				Expect(err).NotTo(HaveOccurred())
				Expect(networker.NetInCallCount()).To(Equal(1))

				actualHandle, actualExtPort, actualContainerPort := networker.NetInArgsForCall(0)
				Expect(actualHandle).To(Equal(container.Handle()))
				Expect(actualExtPort).To(Equal(externalPort))
				Expect(actualContainerPort).To(Equal(contianerPort))
			})

			Context("when networker returns an error", func() {
				It("returns the error", func() {
					networker.NetInReturns(uint32(0), uint32(0), fmt.Errorf("error"))

					_, _, err := container.NetIn(externalPort, contianerPort)

					Expect(err).To(MatchError("error"))
				})
			})
		})
	})
Example #7
0
var _ = Describe("Rootfs container create parameter", func() {
	var container garden.Container
	var args []string

	BeforeEach(func() {
		container = nil
		args = []string{}
	})

	JustBeforeEach(func() {
		client = startGarden(args...)
	})

	AfterEach(func() {
		if container != nil {
			Expect(client.Destroy(container.Handle())).To(Succeed())
		}
	})

	// Temporarily pended until #102455044 is delivered to avoid slow tests
	PDescribe("Garbage Collection", func() {
		Context("when container is deleted", func() {
			It("the graph path is emptied", func() {
				container, err := client.Create(garden.ContainerSpec{RootFSPath: ""})
				Expect(err).ToNot(HaveOccurred())

				err = client.Destroy(container.Handle())
				Expect(err).ToNot(HaveOccurred())

				var size int
				session, err := gexec.Start(exec.Command("sh", "-c", fmt.Sprintf(" du -d0 %s", client.GraphPath)), GinkgoWriter, GinkgoWriter)
Example #8
0
		gardenParms = []string{}
	})

	JustBeforeEach(func() {
		client = startGarden(gardenParms...)

		var err error
		container1, err = client.Create(garden.ContainerSpec{Network: containerNetwork1})
		Expect(err).ToNot(HaveOccurred())

		if len(containerNetwork2) > 0 {
			container2, err = client.Create(garden.ContainerSpec{Network: containerNetwork2})
			Expect(err).ToNot(HaveOccurred())
		}

		containerInterface = "w" + strconv.Itoa(GinkgoParallelNode()) + container1.Handle() + "-1"
	})

	AfterEach(func() {
		if container1 != nil {
			err := client.Destroy(container1.Handle())
			Expect(err).ToNot(HaveOccurred())
		}

		if container2 != nil {
			err := client.Destroy(container2.Handle())
			Expect(err).ToNot(HaveOccurred())
		}
	})

	Context("when the Network parameter is a subnet address", func() {
		var container garden.Container

		BeforeEach(func() {
			var err error

			container, err = client.Create(garden.ContainerSpec{
				Properties: garden.Properties{
					"foo": "bar",
					"a":   "b",
				},
			})
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			client.Destroy(container.Handle())
		})

		Describe("info for one container", func() {
			It("includes the properties", func() {
				info, err := container.Info()
				Expect(err).ToNot(HaveOccurred())

				Expect(info.Properties["foo"]).To(Equal("bar"))
				Expect(info.Properties["a"]).To(Equal("b"))

				Expect(info.Properties).To(HaveLen(2))
			})
		})

		Describe("getting container properties without getting info", func() {
				container = createContainer(gardenClient, garden.ContainerSpec{Privileged: false})
			})

			PIt("allows containers to be destroyed when wshd isn't running", func() {
				info, _ := container.Info()
				pidFile, err := os.Open(filepath.Join(info.ContainerPath, "run", "wshd.pid"))
				Ω(err).ShouldNot(HaveOccurred())

				var pid int
				_, err = fmt.Fscanf(pidFile, "%d", &pid)
				Ω(err).ShouldNot(HaveOccurred())

				_, _, err = runCommand("sudo kill -9 " + strconv.Itoa(pid))
				Ω(err).ShouldNot(HaveOccurred())

				err = gardenClient.Destroy(container.Handle())
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("can send TERM and KILL signals to processes (#83231270)", func() {
				buffer := gbytes.NewBuffer()
				process, err := container.Run(garden.ProcessSpec{
					User: "******",
					Path: "sh",
					Args: []string{"-c", `
						trap 'echo "TERM received"' TERM
						echo trapping
						while true; do echo waiting; sleep 1; done
					`},
				}, recordedProcessIO(buffer))
				Ω(err).ShouldNot(HaveOccurred())
Example #11
0
var _ = Describe("Creating a Container", func() {
	var client *runner.RunningGarden
	var container garden.Container

	Context("after creating a container", func() {
		BeforeEach(func() {
			client = startGarden()

			var err error
			container, err = client.Create(garden.ContainerSpec{})
			Expect(err).NotTo(HaveOccurred())
		})

		It("should create a depot subdirectory based on the container handle", func() {
			Expect(container.Handle()).NotTo(BeEmpty())
			Expect(filepath.Join(client.DepotDir, container.Handle())).To(BeADirectory())
			Expect(filepath.Join(client.DepotDir, container.Handle(), "config.json")).To(BeARegularFile())
		})

		DescribeTable("placing the container in to all namespaces", func(ns string) {
			pid := initProcessPID(container.Handle())
			hostNS, err := gexec.Start(exec.Command("ls", "-l", fmt.Sprintf("/proc/1/ns/%s", ns)), GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			containerNS, err := gexec.Start(exec.Command("ls", "-l", fmt.Sprintf("/proc/%d/ns/%s", pid, ns)), GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(containerNS).Should(gexec.Exit(0))
			Eventually(hostNS).Should(gexec.Exit(0))
Example #12
0
		client = startGarden()
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	Context("after creating a container without a specified handle", func() {
		var initProcPid int

		BeforeEach(func() {
			var err error
			container, err = client.Create(garden.ContainerSpec{})
			Expect(err).NotTo(HaveOccurred())

			initProcPid = initProcessPID(container.Handle())
		})

		It("should create a depot subdirectory based on the container handle", func() {
			Expect(container.Handle()).NotTo(BeEmpty())
			Expect(filepath.Join(client.DepotDir, container.Handle())).To(BeADirectory())
			Expect(filepath.Join(client.DepotDir, container.Handle(), "config.json")).To(BeARegularFile())
		})

		It("should lookup the right container", func() {
			lookupContainer, lookupError := client.Lookup(container.Handle())

			Expect(lookupError).NotTo(HaveOccurred())
			Expect(lookupContainer).To(Equal(container))
		})
Example #13
0
		gardenArgs = []string{}
		privileged = false
	})

	JustBeforeEach(func() {
		client = startGarden(gardenArgs...)

		var err error

		container, err = client.Create(garden.ContainerSpec{Privileged: privileged})
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		if container != nil {
			err := client.Destroy(container.Handle())
			Expect(err).ToNot(HaveOccurred())
		}
	})

	It("retains the container list", func() {
		restartGarden(gardenArgs...)

		handles := getContainerHandles()
		Expect(handles).To(ContainElement(container.Handle()))
	})

	It("allows us to run processes in the same container before and after restart", func() {
		By("running a process before restart")
		runEcho(container)
Example #14
0
						"executor:owner": ownerName,
					},
				})
				Expect(err).NotTo(HaveOccurred())

				container2, err = gardenClient.Create(garden.ContainerSpec{
					Properties: garden.Properties{
						"executor:owner": ownerName,
					},
				})
				Expect(err).NotTo(HaveOccurred())
			})

			It("deletes those containers (and only those containers)", func() {
				Eventually(func() error {
					_, err := gardenClient.Lookup(container1.Handle())
					return err
				}).Should(HaveOccurred())

				Eventually(func() error {
					_, err := gardenClient.Lookup(container2.Handle())
					return err
				}).Should(HaveOccurred())
			})
		})
	})

	Describe("when started", func() {
		JustBeforeEach(func() {
			process = ginkgomon.Invoke(runner)
		})
Example #15
0
				Expect(err).ToNot(HaveOccurred())

				Expect(containerizer.RunCallCount()).To(Equal(1))
				id, spec, io := containerizer.RunArgsForCall(0)
				Expect(id).To(Equal("banana"))
				Expect(spec).To(Equal(origSpec))
				Expect(io).To(Equal(origIO))
			})

			Context("when the containerizer fails to run a process", func() {
				BeforeEach(func() {
					containerizer.RunReturns(nil, errors.New("lost my banana"))
				})

				It("returns the error", func() {
					_, err := container.Run(garden.ProcessSpec{}, garden.ProcessIO{})
					Expect(err).To(MatchError("lost my banana"))
				})
			})
		})

		Describe("destroying a container", func() {
			It("asks the containerizer to destroy the container", func() {
				Expect(gdnr.Destroy(container.Handle())).To(Succeed())
				Expect(containerizer.DestroyCallCount()).To(Equal(1))
				Expect(containerizer.DestroyArgsForCall(0)).To(Equal(container.Handle()))
			})
		})
	})
})
	googleDNSServer := "8.8.8.8"

	JustBeforeEach(func() {
		client = startGarden()
		c, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())

		tarFile, err := os.Open("../bin/connect_to_remote_url.tar")
		Expect(err).ShouldNot(HaveOccurred())
		defer tarFile.Close()
		err = c.StreamIn(garden.StreamInSpec{Path: "bin", TarStream: tarFile})
		Expect(err).ShouldNot(HaveOccurred())
	})

	AfterEach(func() {
		err := client.Destroy(c.Handle())
		Expect(err).ShouldNot(HaveOccurred())
	})

	testConnection := func(protocol, address string, port uint16) (garden.Process, error) {
		return c.Run(garden.ProcessSpec{
			Path: "bin/connect_to_remote_url.exe",
			Env: []string{
				fmt.Sprintf("PROTOCOL=%v", protocol),
				fmt.Sprintf("ADDRESS=%v:%v", address, port),
			},
		}, garden.ProcessIO{})
	}

	openPort := func(proto garden.Protocol, port uint16, ip string) {
		rule := garden.NetOutRule{
Example #17
0
		var container garden.Container

		var privilegedContainer bool
		var rootfs string

		JustBeforeEach(func() {
			client = startGarden()

			var err error
			container, err = client.Create(garden.ContainerSpec{Privileged: privilegedContainer, RootFSPath: rootfs})
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			if container != nil {
				Expect(client.Destroy(container.Handle())).To(Succeed())
			}
		})

		BeforeEach(func() {
			privilegedContainer = false
			rootfs = ""
		})

		Context("when the rootfs is a symlink", func() {
			var symlinkDir string

			BeforeEach(func() {
				symlinkDir, err := ioutil.TempDir("", "test-symlink")
				Expect(err).ToNot(HaveOccurred())
Example #18
0
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Container", func() {
	var container garden.Container

	BeforeEach(func() {
		var err error
		container, err = backend.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		Expect(backend.Destroy(container.Handle())).To(Succeed())
	})

	Describe("Streaming", func() {
		var destinationContainer garden.Container

		AfterEach(func() {
			Expect(backend.Destroy(destinationContainer.Handle())).To(Succeed())
		})

		It("can stream to and from container", func() {
			process, err := container.Run(garden.ProcessSpec{
				Path: "sh",
				Args: []string{
					"-exc",
					`
Example #19
0
	Context("a second container", func() {
		var originContainer garden.Container

		JustBeforeEach(func() {
			var err error
			originContainer = container
			container, err = client.Create(garden.ContainerSpec{
				Network: subnet,
			})

			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			Expect(client.Destroy(originContainer.Handle())).To(Succeed())
		})

		It("should have the next IP address", func() {
			buffer := gbytes.NewBuffer()
			proc, err := container.Run(
				garden.ProcessSpec{
					Path: "ifconfig",
					User: "******",
				}, garden.ProcessIO{Stdout: buffer},
			)

			Expect(err).NotTo(HaveOccurred())
			Expect(proc.Wait()).To(Equal(0))

			Expect(buffer).To(gbytes.Say(ipAddress(subnet, 3)))
Example #20
0
				graceTime := 200 * time.Millisecond

				BeforeEach(func() {
					serverBackend.GraceTimeReturns(graceTime)
				})

				It("resets the container's grace time", func() {
					for i := 0; i < 11; i++ {
						time.Sleep(graceTime / 10)
						call()
					}

					before := time.Now()

					Eventually(serverBackend.DestroyCallCount, 2*graceTime).Should(Equal(1))
					Ω(serverBackend.DestroyArgsForCall(0)).Should(Equal(container.Handle()))

					Ω(time.Since(before)).Should(BeNumerically("~", graceTime, 30*time.Millisecond))
				})
			})
		}

		itFailsWhenTheContainerIsNotFound := func(example func() error) {
			Context("when the container is not found", func() {
				It("fails", func() {
					serverBackend.LookupReturns(nil, errors.New("not found"))
					Ω(example()).Should(MatchError("not found"))
				})
			})
		}
Example #21
0
	})

	Describe("IPC namespace", func() {
		var sharedDir string
		var container garden.Container

		BeforeEach(func() {
			var err error
			sharedDir, err = ioutil.TempDir("", "shared-mount")
			Expect(err).ToNot(HaveOccurred())
			Expect(os.MkdirAll(sharedDir, 0755)).To(Succeed())
		})

		AfterEach(func() {
			if container != nil {
				Expect(client.Destroy(container.Handle())).To(Succeed())
			}
			if sharedDir != "" {
				Expect(os.RemoveAll(sharedDir)).To(Succeed())
			}
		})

		It("does not allow shared memory segments in the host to be accessed by the container", func() {
			Expect(copyFile(shmTestBin, path.Join(sharedDir, "shm_test"))).To(Succeed())

			client = startGarden()
			var err error
			container, err = client.Create(garden.ContainerSpec{
				Privileged: true,
				BindMounts: []garden.BindMount{{
					SrcPath: sharedDir,
Example #22
0
var _ = Describe("Destroying a Container", func() {
	var (
		client    *runner.RunningGarden
		container garden.Container
	)

	BeforeEach(func() {
		client = startGarden()
	})

	AfterEach(func() {
		Expect(client.DestroyAndStop()).To(Succeed())
	})

	JustBeforeEach(func() {
		Expect(client.Destroy(container.Handle())).To(Succeed())
	})

	Context("when running a process", func() {
		var (
			process     garden.Process
			initProcPid int
		)

		BeforeEach(func() {
			var err error

			container, err = client.Create(garden.ContainerSpec{})
			Expect(err).NotTo(HaveOccurred())

			initProcPid = initProcessPID(container.Handle())
		var container garden.Container

		BeforeEach(func() {
			var err error

			container, err = client.Create(garden.ContainerSpec{
				Properties: garden.Properties{
					"foo": "bar",
					"a":   "b",
				},
			})
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			client.Destroy(container.Handle())
		})

		Describe("info for one container", func() {
			It("includes the properties", func() {
				info, err := container.Info()
				Expect(err).ToNot(HaveOccurred())

				Expect(info.Properties["foo"]).To(Equal("bar"))
				Expect(info.Properties["a"]).To(Equal("b"))

				Expect(info.Properties).To(HaveLen(2))
			})
		})

		Describe("getting container properties without getting info", func() {
Example #24
0
func ifNamePrefix(container garden.Container) string {
	return "w" + strconv.Itoa(GinkgoParallelNode()) + container.Handle()
}
Example #25
0
	})

	JustBeforeEach(func() {
		var err error

		client := New(fakeConnection)

		fakeConnection.CreateReturns("some-handle", nil)

		container, err = client.Create(garden.ContainerSpec{})
		Ω(err).ShouldNot(HaveOccurred())
	})

	Describe("Handle", func() {
		It("returns the container's handle", func() {
			Ω(container.Handle()).Should(Equal("some-handle"))
		})
	})

	Describe("Stop", func() {
		It("sends a stop request", func() {
			err := container.Stop(true)
			Ω(err).ShouldNot(HaveOccurred())

			handle, kill := fakeConnection.StopArgsForCall(0)
			Ω(handle).Should(Equal("some-handle"))
			Ω(kill).Should(BeTrue())
		})

		Context("when stopping fails", func() {
			disaster := errors.New("oh no!")
Example #26
0
				Expect(containerizer.CreateArgsForCall(0).RootFSPath).To(Equal("the-volumized-rootfs-path"))
			})

			PIt("destroys volumes when creating fails", func() {})

			Context("when a handle is specified", func() {
				BeforeEach(func() {
					spec.Handle = "the-handle"
				})

				It("passes the handle to the containerizer", func() {
					Expect(containerizer.CreateArgsForCall(0).Handle).To(Equal("the-handle"))
				})

				It("remembers the handle", func() {
					Expect(createdContainer.Handle()).To(Equal("the-handle"))
				})

				PContext("and it is already in use", func() {})
			})

			Context("when a handle is not specified", func() {
				PIt("assigns a handle", func() {
				})
			})

			PContext("when creating the container fails", func() {
			})

			Context("looking up a container and running a process", func() {
				var (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Lifecycle", func() {
	var c garden.Container
	var err error

	JustBeforeEach(func() {
		client = startGarden()
		c, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	AfterEach(func() {
		err := client.Destroy(c.Handle())
		Expect(err).ShouldNot(HaveOccurred())
	})

	Describe("process", func() {
		It("pid is returned", func() {
			tarFile, err := os.Open("../bin/consume.tar")
			Expect(err).ShouldNot(HaveOccurred())
			defer tarFile.Close()

			err = c.StreamIn(garden.StreamInSpec{Path: "bin", TarStream: tarFile})
			Expect(err).ShouldNot(HaveOccurred())

			buf := make([]byte, 0, 1024*1024)
			stdout := bytes.NewBuffer(buf)
Example #28
0
				cmd := exec.Command("ip", "a")
				Expect(cmd.CombinedOutput()).ToNot(ContainSubstring(bridgeEvidence))
			})
		})

		Context("when garden is shut down cleanly and restarted, and the containers are deleted", func() {
			BeforeEach(func() {
				stopGarden()

				client = startGarden()
				Expect(client.Ping()).ToNot(HaveOccurred())

				cmd := exec.Command("ip", "a")
				Expect(cmd.CombinedOutput()).To(ContainSubstring(bridgeEvidence))

				Expect(client.Destroy(ctr1.Handle())).To(Succeed())
				Expect(client.Destroy(ctr2.Handle())).To(Succeed())
			})

			It("the subnet's bridge no longer exists", func() {
				cmd := exec.Command("ip", "a")
				Expect(cmd.CombinedOutput()).ToNot(ContainSubstring(bridgeEvidence))
			})
		})

		Context("when garden is shut down and restarted", func() {
			BeforeEach(func() {
				stopGarden()

				client = startGarden()
				Expect(client.Ping()).ToNot(HaveOccurred())
Example #29
0
					RootFSPath: "docker:///busybox",
				})
				Expect(err).NotTo(HaveOccurred())

				response, err := http.Get(fmt.Sprintf("http://%s/debug/vars", debugAddr))
				Expect(err).ToNot(HaveOccurred())

				contents, err := ioutil.ReadAll(response.Body)
				Expect(err).ToNot(HaveOccurred())

				vars = make(map[string]interface{})
				Expect(json.Unmarshal(contents, &vars)).To(Succeed())
			})

			AfterEach(func() {
				Expect(client.Destroy(container.Handle())).To(Succeed())
			})

			It("exposes the number of loop devices", func() {
				Expect(vars["loopDevices"]).To(BeNumerically(">=", float64(1)))
			})

			It("exposes the number of depot directories", func() {
				Expect(vars["depotDirs"]).To(Equal(float64(1)))
			})

			It("exposes the number of backing stores", func() {
				Expect(vars["backingStores"]).To(Equal(float64(1)))
			})

			Context("when the container does not have a limit", func() {
		container, err = client.Create(garden.ContainerSpec{})
		Expect(err).ToNot(HaveOccurred())
	})

	Context("when a request takes longer than the grace time", func() {
		It("is not destroyed after the request is over", func() {
			process, err := container.Run(garden.ProcessSpec{
				User: "******",
				Path: "sleep",
				Args: []string{"5"},
			}, garden.ProcessIO{})
			Expect(err).ToNot(HaveOccurred())

			Expect(process.Wait()).To(Equal(0))

			_, err = container.Info()
			Expect(err).ToNot(HaveOccurred())
		})
	})

	Context("when no requests are made for longer than the grace time", func() {
		It("is destroyed", func() {
			Eventually(func() error {
				_, err := client.Lookup(container.Handle())
				return err
			}, 10, 1).Should(HaveOccurred())
		})
	})
})