diff options
author | Jhon Honce <jhonce@redhat.com> | 2021-08-02 14:09:55 -0700 |
---|---|---|
committer | Jhon Honce <jhonce@redhat.com> | 2021-08-24 16:36:10 -0700 |
commit | 1dc6d14735eef1e51368103aefba3d7c704dcfe3 (patch) | |
tree | 61109c0b3d99cb3bcf85f53b0f8a837a995b0569 /pkg/bindings/test | |
parent | e9daaf62e3921b8c696f3abd92f001a9447c8aa1 (diff) | |
download | podman-1dc6d14735eef1e51368103aefba3d7c704dcfe3.tar.gz podman-1dc6d14735eef1e51368103aefba3d7c704dcfe3.tar.bz2 podman-1dc6d14735eef1e51368103aefba3d7c704dcfe3.zip |
Fix file descriptor leaks and add test
* Add response.Body.Close() where needed to release HTTP
connections to API server.
* Add tests to ensure no general leaks occur. 100% coverage would be
required to ensure no leaks on any call.
* Update code comments to be godoc correct
Signed-off-by: Jhon Honce <jhonce@redhat.com>
Diffstat (limited to 'pkg/bindings/test')
-rw-r--r-- | pkg/bindings/test/attach_test.go | 5 | ||||
-rw-r--r-- | pkg/bindings/test/common_test.go | 21 | ||||
-rw-r--r-- | pkg/bindings/test/resource_test.go | 116 |
3 files changed, 134 insertions, 8 deletions
diff --git a/pkg/bindings/test/attach_test.go b/pkg/bindings/test/attach_test.go index fbdf18d44..5c3ec48e4 100644 --- a/pkg/bindings/test/attach_test.go +++ b/pkg/bindings/test/attach_test.go @@ -81,10 +81,9 @@ var _ = Describe("Podman containers attach", func() { tickTock := time.NewTimer(2 * time.Second) go func() { <-tickTock.C - timeout := uint(5) - err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(timeout)) + err := containers.Stop(bt.conn, ctnr.ID, new(containers.StopOptions).WithTimeout(uint(5))) if err != nil { - GinkgoWriter.Write([]byte(err.Error())) + fmt.Fprint(GinkgoWriter, err.Error()) } }() diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index 9bac4b620..91ebe21fc 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -8,6 +8,7 @@ import ( "os/exec" "path/filepath" "strings" + "time" "github.com/containers/podman/v3/libpod/define" . "github.com/containers/podman/v3/pkg/bindings" @@ -150,11 +151,21 @@ func createTempDirInTempDir() (string, error) { } func (b *bindingTest) startAPIService() *gexec.Session { - var ( - cmd []string - ) - cmd = append(cmd, "--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock) - return b.runPodman(cmd) + cmd := []string{"--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock} + session := b.runPodman(cmd) + + sock := strings.TrimPrefix(b.sock, "unix://") + for i := 0; i < 10; i++ { + if _, err := os.Stat(sock); err != nil { + if !os.IsNotExist(err) { + break + } + time.Sleep(time.Second) + continue + } + break + } + return session } func (b *bindingTest) cleanup() { diff --git a/pkg/bindings/test/resource_test.go b/pkg/bindings/test/resource_test.go new file mode 100644 index 000000000..b12d1ccd6 --- /dev/null +++ b/pkg/bindings/test/resource_test.go @@ -0,0 +1,116 @@ +package test_bindings + +import ( + "context" + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "reflect" + "strconv" + "syscall" + + "github.com/containers/podman/v3/pkg/bindings" + "github.com/containers/podman/v3/pkg/bindings/containers" + "github.com/containers/podman/v3/pkg/bindings/images" + "github.com/containers/podman/v3/pkg/bindings/pods" + "github.com/containers/podman/v3/pkg/bindings/system" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Verify Podman resources", func() { + var ( + bt *bindingTest + s *Session + ) + + BeforeEach(func() { + bt = newBindingTest() + s = bt.startAPIService() + err := bt.NewConnection() + Expect(err).ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + s.Kill() + bt.cleanup() + }) + + It("no leaked connections", func() { + conn, err := bindings.NewConnection(context.Background(), bt.sock) + Expect(err).ShouldNot(HaveOccurred()) + + // Record details on open file descriptors before using API + buffer := lsof() + + // Record open fd from /proc + start, err := readProc() + Expect(err).ShouldNot(HaveOccurred()) + + // Run some operations + _, err = system.Info(conn, nil) + Expect(err).ShouldNot(HaveOccurred()) + _, err = images.List(conn, nil) + Expect(err).ShouldNot(HaveOccurred()) + _, err = containers.List(conn, nil) + Expect(err).ShouldNot(HaveOccurred()) + _, err = pods.List(conn, nil) + Expect(err).ShouldNot(HaveOccurred()) + + podman, _ := bindings.GetClient(conn) + podman.Client.CloseIdleConnections() + + // Record open fd from /proc + finished, err := readProc() + Expect(err).ShouldNot(HaveOccurred()) + if !reflect.DeepEqual(finished, start) { + fmt.Fprintf(GinkgoWriter, "Open FDs:\nlsof Before:\n%s\n", buffer) + + // Record details on open file descriptors after using API + buffer := lsof() + fmt.Fprintf(GinkgoWriter, "lsof After:\n%s\n", buffer) + + // We know test has failed. Easier to let ginkgo format output. + Expect(finished).Should(Equal(start)) + } + }) +}) + +func lsof() string { + lsof := exec.Command("lsof", "+E", "-p", strconv.Itoa(os.Getpid())) + buffer, err := lsof.Output() + Expect(err).ShouldNot(HaveOccurred()) + return string(buffer) +} + +func readProc() ([]string, error) { + syscall.Sync() + + names := make([]string, 0) + err := filepath.WalkDir(fmt.Sprintf("/proc/%d/fd", os.Getpid()), + func(path string, d fs.DirEntry, err error) error { + name := path + " -> " + + switch { + case d.IsDir(): + return nil + case err != nil: + name += err.Error() + case d.Type()&fs.ModeSymlink != 0: + n, err := os.Readlink(path) + if err != nil && !os.IsNotExist(err) { + return err + } + if n == "" { + n = d.Type().String() + } + name += n + } + names = append(names, name) + return nil + }) + return names, err +} |