summaryrefslogtreecommitdiff
path: root/pkg/bindings/test/resource_test.go
blob: 8da2178ef656045bcad25cfa1c99dc0784d479b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package bindings_test

import (
	"context"
	"fmt"
	"io/fs"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strconv"
	"syscall"

	"github.com/containers/podman/v4/pkg/bindings"
	"github.com/containers/podman/v4/pkg/bindings/containers"
	"github.com/containers/podman/v4/pkg/bindings/images"
	"github.com/containers/podman/v4/pkg/bindings/pods"
	"github.com/containers/podman/v4/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
}