From d1c26af144b314f30cd69d42e33ab8cbacb080ff Mon Sep 17 00:00:00 2001
From: Brent Baude <bbaude@redhat.com>
Date: Sat, 14 Mar 2020 14:01:20 -0500
Subject: [PATCH] apiv2 add bindings for logs|events

add go-bindings for logs and events. tests were also added.

Signed-off-by: Brent Baude <bbaude@redhat.com>
---
 pkg/api/handlers/compat/containers.go |   2 -
 pkg/api/server/register_events.go     |   2 +-
 pkg/bindings/bindings.go              |   9 ++
 pkg/bindings/containers/containers.go |   1 -
 pkg/bindings/containers/logs.go       | 116 ++++++++++++++++++++++++++
 pkg/bindings/containers/types.go      |  13 +++
 pkg/bindings/system/system.go         |  61 ++++++++++++++
 pkg/bindings/test/common_test.go      |   2 +-
 pkg/bindings/test/containers_test.go  |  70 ++++++++++------
 pkg/bindings/test/images_test.go      |  26 +++---
 pkg/bindings/test/pods_test.go        |  13 ++-
 pkg/bindings/test/system_test.go      |  51 +++++++++++
 pkg/bindings/test/volumes_test.go     |   3 +-
 13 files changed, 317 insertions(+), 52 deletions(-)
 create mode 100644 pkg/bindings/containers/logs.go
 create mode 100644 pkg/bindings/containers/types.go
 create mode 100644 pkg/bindings/system/system.go
 create mode 100644 pkg/bindings/test/system_test.go

diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 1298e7fa4d..74907f0f7b 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -326,7 +326,6 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
 				builder.WriteRune(' ')
 			}
 			builder.WriteString(line.Msg)
-
 			// Build header and output entry
 			binary.BigEndian.PutUint32(header[4:], uint32(len(header)+builder.Len()))
 			if _, err := w.Write(header[:]); err != nil {
@@ -335,7 +334,6 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
 			if _, err := fmt.Fprint(w, builder.String()); err != nil {
 				log.Errorf("unable to write builder string: %q", err)
 			}
-
 			if flusher, ok := w.(http.Flusher); ok {
 				flusher.Flush()
 			}
diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go
index b0f403709a..e909303da8 100644
--- a/pkg/api/server/register_events.go
+++ b/pkg/api/server/register_events.go
@@ -63,6 +63,6 @@ func (s *APIServer) registerEventsHandlers(r *mux.Router) error {
 	//     description: returns a string of json data describing an event
 	//   500:
 	//     "$ref": "#/responses/InternalError"
-	r.Handle(VersionedPath("/events"), s.APIHandler(compat.GetEvents)).Methods(http.MethodGet)
+	r.Handle(VersionedPath("/libpod/events"), s.APIHandler(compat.GetEvents)).Methods(http.MethodGet)
 	return nil
 }
diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go
index e83c4a5e16..4b07847d1a 100644
--- a/pkg/bindings/bindings.go
+++ b/pkg/bindings/bindings.go
@@ -7,3 +7,12 @@
 // is established, users can then manage the Podman container runtime.
 
 package bindings
+
+var (
+	// PTrue is a convenience variable that can be used in bindings where
+	// a pointer to a bool (optional parameter) is required.
+	PTrue bool = true
+	// PFalse is a convenience variable that can be used in bindings where
+	// a pointer to a bool (optional parameter) is required.
+	PFalse bool = false
+)
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 670321f213..f298dbba13 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -139,7 +139,6 @@ func Kill(ctx context.Context, nameOrID string, signal string) error {
 	return response.Process(nil)
 
 }
-func Logs() {}
 
 // Pause pauses a given container.  The nameOrID can be a container name
 // or a partial/full ID.
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
new file mode 100644
index 0000000000..b7ecb3c7e0
--- /dev/null
+++ b/pkg/bindings/containers/logs.go
@@ -0,0 +1,116 @@
+package containers
+
+import (
+	"context"
+	"encoding/binary"
+	"io"
+	"net/http"
+	"net/url"
+	"strconv"
+
+	"github.com/containers/libpod/pkg/bindings"
+	"github.com/pkg/errors"
+)
+
+// Logs obtains a container's logs given the options provided.  The logs are then sent to the
+// stdout|stderr channels as strings.
+func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, stderrChan chan string) error {
+	conn, err := bindings.GetClient(ctx)
+	if err != nil {
+		return err
+	}
+	params := url.Values{}
+	if opts.Follow != nil {
+		params.Set("follow", strconv.FormatBool(*opts.Follow))
+	}
+	if opts.Since != nil {
+		params.Set("since", *opts.Since)
+	}
+	if opts.Stderr != nil {
+		params.Set("stderr", strconv.FormatBool(*opts.Stderr))
+	}
+	if opts.Stdout != nil {
+		params.Set("stdout", strconv.FormatBool(*opts.Stdout))
+	}
+	if opts.Tail != nil {
+		params.Set("tail", *opts.Tail)
+	}
+	if opts.Timestamps != nil {
+		params.Set("timestamps", strconv.FormatBool(*opts.Timestamps))
+	}
+	if opts.Until != nil {
+		params.Set("until", *opts.Until)
+	}
+	// The API requires either stdout|stderr be used. If neither are specified, we specify stdout
+	if opts.Stdout == nil && opts.Stderr == nil {
+		params.Set("stdout", strconv.FormatBool(true))
+	}
+	response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nameOrID)
+	if err != nil {
+		return err
+	}
+
+	// read 8 bytes
+	// first byte determines stderr=2|stdout=1
+	// bytes 4-7 len(msg) in uint32
+	for {
+		stream, msgSize, err := readHeader(response.Body)
+		if err != nil {
+			// In case the server side closes up shop because !follow
+			if err == io.EOF {
+				break
+			}
+			return errors.Wrap(err, "unable to read log header")
+		}
+		msg, err := readMsg(response.Body, msgSize)
+		if err != nil {
+			return errors.Wrap(err, "unable to read log message")
+		}
+		if stream == 1 {
+			stdoutChan <- msg
+		} else {
+			stderrChan <- msg
+		}
+	}
+	return nil
+}
+
+func readMsg(r io.Reader, msgSize int) (string, error) {
+	var msg []byte
+	size := msgSize
+	for {
+		b := make([]byte, size)
+		_, err := r.Read(b)
+		if err != nil {
+			return "", err
+		}
+		msg = append(msg, b...)
+		if len(msg) == msgSize {
+			break
+		}
+		size = msgSize - len(msg)
+	}
+	return string(msg), nil
+}
+
+func readHeader(r io.Reader) (byte, int, error) {
+	var (
+		header []byte
+		size   = 8
+	)
+	for {
+		b := make([]byte, size)
+		_, err := r.Read(b)
+		if err != nil {
+			return 0, 0, err
+		}
+		header = append(header, b...)
+		if len(header) == 8 {
+			break
+		}
+		size = 8 - len(header)
+	}
+	stream := header[0]
+	msgSize := int(binary.BigEndian.Uint32(header[4:]) - 8)
+	return stream, msgSize, nil
+}
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
new file mode 100644
index 0000000000..87342f7eab
--- /dev/null
+++ b/pkg/bindings/containers/types.go
@@ -0,0 +1,13 @@
+package containers
+
+// LogOptions describe finer control of log content or
+// how the content is formatted.
+type LogOptions struct {
+	Follow     *bool
+	Since      *string
+	Stderr     *bool
+	Stdout     *bool
+	Tail       *string
+	Timestamps *bool
+	Until      *string
+}
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
new file mode 100644
index 0000000000..fce8bbb8e3
--- /dev/null
+++ b/pkg/bindings/system/system.go
@@ -0,0 +1,61 @@
+package system
+
+import (
+	"context"
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/url"
+
+	"github.com/containers/libpod/pkg/api/handlers"
+	"github.com/containers/libpod/pkg/bindings"
+	"github.com/pkg/errors"
+	"github.com/sirupsen/logrus"
+)
+
+// Events allows you to monitor libdpod related events like container creation and
+// removal.  The events are then passed to the eventChan provided. The optional cancelChan
+// can be used to cancel the read of events and close down the HTTP connection.
+func Events(ctx context.Context, eventChan chan (handlers.Event), cancelChan chan bool, since, until *string, filters map[string][]string) error {
+	conn, err := bindings.GetClient(ctx)
+	if err != nil {
+		return err
+	}
+	params := url.Values{}
+	if since != nil {
+		params.Set("since", *since)
+	}
+	if until != nil {
+		params.Set("until", *until)
+	}
+	if filters != nil {
+		filterString, err := bindings.FiltersToString(filters)
+		if err != nil {
+			return errors.Wrap(err, "invalid filters")
+		}
+		params.Set("filters", filterString)
+	}
+	response, err := conn.DoRequest(nil, http.MethodGet, "/events", params)
+	if err != nil {
+		return err
+	}
+	if cancelChan != nil {
+		go func() {
+			<-cancelChan
+			err = response.Body.Close()
+			logrus.Error(errors.Wrap(err, "unable to close event response body"))
+		}()
+	}
+	dec := json.NewDecoder(response.Body)
+	for {
+		e := handlers.Event{}
+		if err := dec.Decode(&e); err != nil {
+			if err == io.EOF {
+				break
+			}
+			return errors.Wrap(err, "unable to decode event response")
+		}
+		eventChan <- e
+	}
+	return nil
+}
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 5cd8f7e4f5..409e620a33 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -152,7 +152,7 @@ func (b *bindingTest) startAPIService() *gexec.Session {
 	var (
 		cmd []string
 	)
-	cmd = append(cmd, "--log-level=debug", "system", "service", "--timeout=0", b.sock)
+	cmd = append(cmd, "--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock)
 	return b.runPodman(cmd)
 }
 
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 34a9c31369..afb0cc19b6 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -3,10 +3,12 @@ package test_bindings
 import (
 	"net/http"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/containers/libpod/pkg/bindings"
 	"github.com/containers/libpod/pkg/bindings/containers"
+	"github.com/containers/libpod/pkg/specgen"
 	"github.com/containers/libpod/test/utils"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
@@ -15,11 +17,9 @@ import (
 
 var _ = Describe("Podman containers ", func() {
 	var (
-		bt        *bindingTest
-		s         *gexec.Session
-		err       error
-		falseFlag bool = false
-		trueFlag  bool = true
+		bt  *bindingTest
+		s   *gexec.Session
+		err error
 	)
 
 	BeforeEach(func() {
@@ -55,7 +55,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a running container by name", func() {
 		// Pausing by name should work
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, name)
 		Expect(err).To(BeNil())
@@ -69,7 +69,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a running container by id", func() {
 		// Pausing by id should work
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, cid)
 		Expect(err).To(BeNil())
@@ -83,7 +83,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman unpause a running container by name", func() {
 		// Unpausing by name should work
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, name)
 		Expect(err).To(BeNil())
@@ -99,7 +99,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman unpause a running container by ID", func() {
 		// Unpausing by ID should work
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		// Pause by name
 		err = containers.Pause(bt.conn, name)
@@ -118,7 +118,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a paused container by name", func() {
 		// Pausing a paused container by name should fail
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, name)
 		Expect(err).To(BeNil())
@@ -131,7 +131,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a paused container by id", func() {
 		// Pausing a paused container by id should fail
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, cid)
 		Expect(err).To(BeNil())
@@ -144,7 +144,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a stopped container by name", func() {
 		// Pausing a stopped container by name should fail
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Stop(bt.conn, name, nil)
 		Expect(err).To(BeNil())
@@ -157,7 +157,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman pause a stopped container by id", func() {
 		// Pausing a stopped container by id should fail
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Stop(bt.conn, cid, nil)
 		Expect(err).To(BeNil())
@@ -170,11 +170,11 @@ var _ = Describe("Podman containers ", func() {
 	It("podman remove a paused container by id without force", func() {
 		// Removing a paused container without force should fail
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, cid)
 		Expect(err).To(BeNil())
-		err = containers.Remove(bt.conn, cid, &falseFlag, &falseFlag)
+		err = containers.Remove(bt.conn, cid, &bindings.PFalse, &bindings.PFalse)
 		Expect(err).ToNot(BeNil())
 		code, _ := bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
@@ -191,18 +191,18 @@ var _ = Describe("Podman containers ", func() {
 
 		// Removing a paused container with force should work
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, cid)
 		Expect(err).To(BeNil())
-		err = containers.Remove(bt.conn, cid, &trueFlag, &falseFlag)
+		err = containers.Remove(bt.conn, cid, &bindings.PTrue, &bindings.PFalse)
 		Expect(err).To(BeNil())
 	})
 
 	It("podman stop a paused container by name", func() {
 		// Stopping a paused container by name should fail
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, name)
 		Expect(err).To(BeNil())
@@ -215,7 +215,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman stop a paused container by id", func() {
 		// Stopping a paused container by id should fail
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Pause(bt.conn, cid)
 		Expect(err).To(BeNil())
@@ -228,7 +228,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman stop a running container by name", func() {
 		// Stopping a running container by name should work
 		var name = "top"
-		_, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Stop(bt.conn, name, nil)
 		Expect(err).To(BeNil())
@@ -242,7 +242,7 @@ var _ = Describe("Podman containers ", func() {
 	It("podman stop a running container by ID", func() {
 		// Stopping a running container by ID should work
 		var name = "top"
-		cid, err := bt.RunTopContainer(&name, &falseFlag, nil)
+		cid, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		err = containers.Stop(bt.conn, cid, nil)
 		Expect(err).To(BeNil())
@@ -301,8 +301,8 @@ var _ = Describe("Podman containers ", func() {
 
 		errChan = make(chan error)
 		go func() {
-			exitCode, err = containers.Wait(bt.conn, name, &unpause)
-			errChan <- err
+			_, waitErr := containers.Wait(bt.conn, name, &unpause)
+			errChan <- waitErr
 			close(errChan)
 		}()
 		err = containers.Unpause(bt.conn, name)
@@ -323,7 +323,7 @@ var _ = Describe("Podman containers ", func() {
 
 		// a container that has no healthcheck should be a 409
 		var name = "top"
-		bt.RunTopContainer(&name, &falseFlag, nil)
+		bt.RunTopContainer(&name, &bindings.PFalse, nil)
 		_, err = containers.RunHealthCheck(bt.conn, name)
 		Expect(err).ToNot(BeNil())
 		code, _ = bindings.CheckResponseCode(err)
@@ -357,4 +357,26 @@ var _ = Describe("Podman containers ", func() {
 		//Expect(code).To(BeNumerically("==", http.StatusConflict))
 	})
 
+	It("logging", func() {
+		stdoutChan := make(chan string, 10)
+		s := specgen.NewSpecGenerator(alpine.name)
+		s.Terminal = true
+		s.Command = []string{"date", "-R"}
+		r, err := containers.CreateWithSpec(bt.conn, s)
+		Expect(err).To(BeNil())
+		err = containers.Start(bt.conn, r.ID, nil)
+		Expect(err).To(BeNil())
+
+		_, err = containers.Wait(bt.conn, r.ID, nil)
+		Expect(err).To(BeNil())
+
+		opts := containers.LogOptions{Stdout: &bindings.PTrue, Follow: &bindings.PTrue}
+		go func() {
+			containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil)
+		}()
+		o := <-stdoutChan
+		o = strings.ReplaceAll(o, "\r", "")
+		_, err = time.Parse(time.RFC1123Z, o)
+		Expect(err).To(BeNil())
+	})
 })
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 17b3b254ac..5e4cfe7be3 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -19,11 +19,9 @@ var _ = Describe("Podman images", func() {
 		//tempdir    string
 		//err        error
 		//podmanTest *PodmanTestIntegration
-		bt        *bindingTest
-		s         *gexec.Session
-		err       error
-		falseFlag bool = false
-		trueFlag  bool = true
+		bt  *bindingTest
+		s   *gexec.Session
+		err error
 	)
 
 	BeforeEach(func() {
@@ -76,7 +74,7 @@ var _ = Describe("Podman images", func() {
 		//Expect(data.Size).To(BeZero())
 
 		// Enabling the size parameter should result in size being populated
-		data, err = images.GetImage(bt.conn, alpine.name, &trueFlag)
+		data, err = images.GetImage(bt.conn, alpine.name, &bindings.PTrue)
 		Expect(err).To(BeNil())
 		Expect(data.Size).To(BeNumerically(">", 0))
 	})
@@ -84,7 +82,7 @@ var _ = Describe("Podman images", func() {
 	// Test to validate the remove image api
 	It("remove image", func() {
 		// Remove invalid image should be a 404
-		_, err = images.Remove(bt.conn, "foobar5000", &falseFlag)
+		_, err = images.Remove(bt.conn, "foobar5000", &bindings.PFalse)
 		Expect(err).ToNot(BeNil())
 		code, _ := bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusNotFound))
@@ -101,21 +99,21 @@ var _ = Describe("Podman images", func() {
 
 		// Start a container with alpine image
 		var top string = "top"
-		_, err = bt.RunTopContainer(&top, &falseFlag, nil)
+		_, err = bt.RunTopContainer(&top, &bindings.PFalse, nil)
 		Expect(err).To(BeNil())
 		// we should now have a container called "top" running
-		containerResponse, err := containers.Inspect(bt.conn, "top", &falseFlag)
+		containerResponse, err := containers.Inspect(bt.conn, "top", &bindings.PFalse)
 		Expect(err).To(BeNil())
 		Expect(containerResponse.Name).To(Equal("top"))
 
 		// try to remove the image "alpine". This should fail since we are not force
 		// deleting hence image cannot be deleted until the container is deleted.
-		response, err = images.Remove(bt.conn, alpine.shortName, &falseFlag)
+		response, err = images.Remove(bt.conn, alpine.shortName, &bindings.PFalse)
 		code, _ = bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
 
 		// Removing the image "alpine" where force = true
-		response, err = images.Remove(bt.conn, alpine.shortName, &trueFlag)
+		response, err = images.Remove(bt.conn, alpine.shortName, &bindings.PTrue)
 		Expect(err).To(BeNil())
 
 		// Checking if both the images are gone as well as the container is deleted
@@ -127,7 +125,7 @@ var _ = Describe("Podman images", func() {
 		code, _ = bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusNotFound))
 
-		_, err = containers.Inspect(bt.conn, "top", &falseFlag)
+		_, err = containers.Inspect(bt.conn, "top", &bindings.PFalse)
 		code, _ = bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusNotFound))
 	})
@@ -178,13 +176,13 @@ var _ = Describe("Podman images", func() {
 		// List  images with a filter
 		filters := make(map[string][]string)
 		filters["reference"] = []string{alpine.name}
-		filteredImages, err := images.List(bt.conn, &falseFlag, filters)
+		filteredImages, err := images.List(bt.conn, &bindings.PFalse, filters)
 		Expect(err).To(BeNil())
 		Expect(len(filteredImages)).To(BeNumerically("==", 1))
 
 		// List  images with a bad filter
 		filters["name"] = []string{alpine.name}
-		_, err = images.List(bt.conn, &falseFlag, filters)
+		_, err = images.List(bt.conn, &bindings.PFalse, filters)
 		Expect(err).ToNot(BeNil())
 		code, _ := bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 7e29265b7d..ad0a574d3e 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -14,11 +14,10 @@ import (
 
 var _ = Describe("Podman pods", func() {
 	var (
-		bt       *bindingTest
-		s        *gexec.Session
-		newpod   string
-		err      error
-		trueFlag bool = true
+		bt     *bindingTest
+		s      *gexec.Session
+		newpod string
+		err    error
 	)
 
 	BeforeEach(func() {
@@ -57,7 +56,7 @@ var _ = Describe("Podman pods", func() {
 		Expect(err).To(BeNil())
 		Expect(len(podSummary)).To(Equal(1))
 		// Adding an alpine container to the existing pod
-		_, err = bt.RunTopContainer(nil, &trueFlag, &newpod)
+		_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
 		Expect(err).To(BeNil())
 		podSummary, err = pods.List(bt.conn, nil)
 		// Verify no errors.
@@ -111,7 +110,7 @@ var _ = Describe("Podman pods", func() {
 		Expect(code).To(BeNumerically("==", http.StatusNotFound))
 
 		// Adding an alpine container to the existing pod
-		_, err = bt.RunTopContainer(nil, &trueFlag, &newpod)
+		_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
 		Expect(err).To(BeNil())
 
 		// Binding needs to be modified to inspect the pod state.
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
new file mode 100644
index 0000000000..3abc26b345
--- /dev/null
+++ b/pkg/bindings/test/system_test.go
@@ -0,0 +1,51 @@
+package test_bindings
+
+import (
+	"time"
+
+	"github.com/containers/libpod/pkg/api/handlers"
+	"github.com/containers/libpod/pkg/bindings/system"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Podman system", func() {
+	var (
+		bt *bindingTest
+		s  *gexec.Session
+	)
+
+	BeforeEach(func() {
+		bt = newBindingTest()
+		bt.RestoreImagesFromCache()
+		s = bt.startAPIService()
+		time.Sleep(1 * time.Second)
+		err := bt.NewConnection()
+		Expect(err).To(BeNil())
+	})
+
+	AfterEach(func() {
+		s.Kill()
+		bt.cleanup()
+	})
+
+	It("podman events", func() {
+		eChan := make(chan handlers.Event, 1)
+		var messages []handlers.Event
+		cancelChan := make(chan bool, 1)
+		go func() {
+			for e := range eChan {
+				messages = append(messages, e)
+			}
+		}()
+		go func() {
+			system.Events(bt.conn, eChan, cancelChan, nil, nil, nil)
+		}()
+
+		_, err := bt.RunTopContainer(nil, nil, nil)
+		Expect(err).To(BeNil())
+		cancelChan <- true
+		Expect(len(messages)).To(BeNumerically("==", 3))
+	})
+})
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index b1a742c430..1d5ae1329e 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -25,7 +25,6 @@ var _ = Describe("Podman volumes", func() {
 		s        *gexec.Session
 		connText context.Context
 		err      error
-		trueFlag = true
 	)
 
 	BeforeEach(func() {
@@ -107,7 +106,7 @@ var _ = Describe("Podman volumes", func() {
 		zero := 0
 		err = containers.Stop(connText, "vtest", &zero)
 		Expect(err).To(BeNil())
-		err = volumes.Remove(connText, vol.Name, &trueFlag)
+		err = volumes.Remove(connText, vol.Name, &bindings.PTrue)
 		Expect(err).To(BeNil())
 	})