From 04f2f95bb4ffae161ff0e7f01e381d6c7296fe14 Mon Sep 17 00:00:00 2001
From: baude <bbaude@redhat.com>
Date: Sun, 11 Aug 2019 11:47:15 -0500
Subject: Create framework for varlink endpoint integration tests

add the ability to write integration tests similar to our e2e tests for
the varlink endpoints.

Signed-off-by: baude <bbaude@redhat.com>
---
 test/endpoint/config.go              |  22 ++++
 test/endpoint/endpoint.go            | 218 ++++++++++++++++++++++++++++++++++
 test/endpoint/endpoint_suite_test.go |  70 +++++++++++
 test/endpoint/exists_test.go         |  66 +++++++++++
 test/endpoint/pull_test.go           |  44 +++++++
 test/endpoint/setup.go               | 219 +++++++++++++++++++++++++++++++++++
 test/endpoint/version_test.go        |  41 +++++++
 7 files changed, 680 insertions(+)
 create mode 100644 test/endpoint/config.go
 create mode 100644 test/endpoint/endpoint.go
 create mode 100644 test/endpoint/endpoint_suite_test.go
 create mode 100644 test/endpoint/exists_test.go
 create mode 100644 test/endpoint/pull_test.go
 create mode 100644 test/endpoint/setup.go
 create mode 100644 test/endpoint/version_test.go

(limited to 'test')

diff --git a/test/endpoint/config.go b/test/endpoint/config.go
new file mode 100644
index 000000000..15ee23547
--- /dev/null
+++ b/test/endpoint/config.go
@@ -0,0 +1,22 @@
+package endpoint
+
+import "encoding/json"
+
+var (
+	STORAGE_FS               = "vfs"
+	STORAGE_OPTIONS          = "--storage-driver vfs"
+	ROOTLESS_STORAGE_FS      = "vfs"
+	ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs"
+	CACHE_IMAGES             = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra, labels}
+	nginx                    = "quay.io/libpod/alpine_nginx:latest"
+	BB_GLIBC                 = "docker.io/library/busybox:glibc"
+	registry                 = "docker.io/library/registry:2"
+	labels                   = "quay.io/libpod/alpine_labels:latest"
+)
+
+func makeNameMessage(name string) string {
+	n := make(map[string]string)
+	n["name"] = name
+	b, _ := json.Marshal(n)
+	return string(b)
+}
diff --git a/test/endpoint/endpoint.go b/test/endpoint/endpoint.go
new file mode 100644
index 000000000..4f9e6055e
--- /dev/null
+++ b/test/endpoint/endpoint.go
@@ -0,0 +1,218 @@
+package endpoint
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
+
+	iopodman "github.com/containers/libpod/cmd/podman/varlink"
+	"github.com/containers/libpod/pkg/rootless"
+	. "github.com/onsi/ginkgo"
+	"github.com/onsi/gomega/gexec"
+)
+
+var (
+	ARTIFACT_DIR       = "/tmp/.artifacts"
+	CGROUP_MANAGER     = "systemd"
+	defaultWaitTimeout = 90
+	//RESTORE_IMAGES     = []string{ALPINE, BB}
+	INTEGRATION_ROOT string
+	ImageCacheDir    = "/tmp/podman/imagecachedir"
+	VarlinkBinary    = "/usr/bin/varlink"
+	ALPINE           = "docker.io/library/alpine:latest"
+	infra            = "k8s.gcr.io/pause:3.1"
+	BB               = "docker.io/library/busybox:latest"
+	redis            = "docker.io/library/redis:alpine"
+	fedoraMinimal    = "registry.fedoraproject.org/fedora-minimal:latest"
+)
+
+type EndpointTestIntegration struct {
+	ArtifactPath  string
+	CNIConfigDir  string
+	CgroupManager string
+	ConmonBinary  string
+	CrioRoot      string
+	//Host                HostOS
+	ImageCacheDir       string
+	ImageCacheFS        string
+	OCIRuntime          string
+	PodmanBinary        string
+	RemoteTest          bool
+	RunRoot             string
+	SignaturePolicyPath string
+	StorageOptions      string
+	TmpDir              string
+	Timings             []string
+	VarlinkBinary       string
+	VarlinkCommand      *exec.Cmd
+	VarlinkEndpoint     string
+	VarlinkSession      *os.Process
+}
+
+func (p *EndpointTestIntegration) StartVarlink() {
+	p.startVarlink(false)
+}
+
+func (p *EndpointTestIntegration) StartVarlinkWithCache() {
+	p.startVarlink(true)
+}
+
+func (p *EndpointTestIntegration) startVarlink(useImageCache bool) {
+	var (
+		counter int
+	)
+	if os.Geteuid() == 0 {
+		os.MkdirAll("/run/podman", 0755)
+	}
+	varlinkEndpoint := p.VarlinkEndpoint
+	//p.SetVarlinkAddress(p.VarlinkEndpoint)
+
+	args := []string{"varlink", "--timeout", "0", varlinkEndpoint}
+	podmanOptions := getVarlinkOptions(p, args)
+	if useImageCache {
+		cacheOptions := []string{"--storage-opt", fmt.Sprintf("%s.imagestore=%s", p.ImageCacheFS, p.ImageCacheDir)}
+		podmanOptions = append(cacheOptions, podmanOptions...)
+	}
+	command := exec.Command(p.PodmanBinary, podmanOptions...)
+	fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
+	command.Start()
+	command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+	p.VarlinkCommand = command
+	p.VarlinkSession = command.Process
+	for {
+		if result := p.endpointReady(); result == 0 {
+			break
+		}
+		fmt.Println("Waiting for varlink connection to become active", counter)
+		time.Sleep(250 * time.Millisecond)
+		counter++
+		if counter > 40 {
+			Fail("varlink endpoint never became ready")
+		}
+	}
+}
+
+func (p *EndpointTestIntegration) endpointReady() int {
+	session := p.Varlink("GetVersion", "", false)
+	return session.ExitCode()
+}
+
+func (p *EndpointTestIntegration) StopVarlink() {
+	var out bytes.Buffer
+	var pids []int
+	varlinkSession := p.VarlinkSession
+
+	if !rootless.IsRootless() {
+		if err := varlinkSession.Kill(); err != nil {
+			fmt.Fprintf(os.Stderr, "error on varlink stop-kill %q", err)
+		}
+		if _, err := varlinkSession.Wait(); err != nil {
+			fmt.Fprintf(os.Stderr, "error on varlink stop-wait %q", err)
+		}
+
+	} else {
+		//p.ResetVarlinkAddress()
+		parentPid := fmt.Sprintf("%d", p.VarlinkSession.Pid)
+		pgrep := exec.Command("pgrep", "-P", parentPid)
+		fmt.Printf("running: pgrep %s\n", parentPid)
+		pgrep.Stdout = &out
+		err := pgrep.Run()
+		if err != nil {
+			fmt.Fprint(os.Stderr, "unable to find varlink pid")
+		}
+
+		for _, s := range strings.Split(out.String(), "\n") {
+			if len(s) == 0 {
+				continue
+			}
+			p, err := strconv.Atoi(s)
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "unable to convert %s to int", s)
+			}
+			if p != 0 {
+				pids = append(pids, p)
+			}
+		}
+
+		pids = append(pids, p.VarlinkSession.Pid)
+		for _, pid := range pids {
+			syscall.Kill(pid, syscall.SIGKILL)
+		}
+	}
+	socket := strings.Split(p.VarlinkEndpoint, ":")[1]
+	if err := os.Remove(socket); err != nil {
+		fmt.Println(err)
+	}
+}
+
+type EndpointSession struct {
+	*gexec.Session
+}
+
+func getVarlinkOptions(p *EndpointTestIntegration, args []string) []string {
+	podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s",
+		p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ")
+	if os.Getenv("HOOK_OPTION") != "" {
+		podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION"))
+	}
+	podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...)
+	podmanOptions = append(podmanOptions, args...)
+	return podmanOptions
+}
+
+func (p *EndpointTestIntegration) Varlink(endpoint, message string, more bool) *EndpointSession {
+	//call unix:/run/user/1000/podman/io.podman/io.podman.GetContainerStats '{"name": "foobar" }'
+	var (
+		command *exec.Cmd
+	)
+
+	args := []string{"call"}
+	if more {
+		args = append(args, "-m")
+	}
+	args = append(args, []string{fmt.Sprintf("%s/io.podman.%s", p.VarlinkEndpoint, endpoint)}...)
+	if len(message) > 0 {
+		args = append(args, message)
+	}
+	command = exec.Command(p.VarlinkBinary, args...)
+	session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
+	if err != nil {
+		Fail(fmt.Sprintf("unable to run varlink command: %s\n%v", strings.Join(args, " "), err))
+	}
+	session.Wait(defaultWaitTimeout)
+	return &EndpointSession{session}
+}
+
+func (s *EndpointSession) OutputToString() string {
+	fields := strings.Fields(fmt.Sprintf("%s", s.Out.Contents()))
+	return strings.Join(fields, " ")
+}
+
+func (s *EndpointSession) OutputToBytes() []byte {
+	out := s.OutputToString()
+	return []byte(out)
+}
+
+func (s *EndpointSession) OutputToStringMap() map[string]string {
+	var out map[string]string
+	json.Unmarshal(s.OutputToBytes(), &out)
+	return out
+}
+
+func (s *EndpointSession) OutputToMapToInt() map[string]int {
+	var out map[string]int
+	json.Unmarshal(s.OutputToBytes(), &out)
+	return out
+}
+
+func (s *EndpointSession) OutputToMoreResponse() iopodman.MoreResponse {
+	out := make(map[string]iopodman.MoreResponse)
+	json.Unmarshal(s.OutputToBytes(), &out)
+	return out["reply"]
+}
diff --git a/test/endpoint/endpoint_suite_test.go b/test/endpoint/endpoint_suite_test.go
new file mode 100644
index 000000000..401da94c2
--- /dev/null
+++ b/test/endpoint/endpoint_suite_test.go
@@ -0,0 +1,70 @@
+package endpoint
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func TestEndpoint(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "Endpoint Suite")
+}
+
+var LockTmpDir string
+
+var _ = SynchronizedBeforeSuite(func() []byte {
+	// Cache images
+	cwd, _ := os.Getwd()
+	INTEGRATION_ROOT = filepath.Join(cwd, "../../")
+	podman := Setup("/tmp")
+	podman.ArtifactPath = ARTIFACT_DIR
+	if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
+		if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
+			fmt.Printf("%q\n", err)
+			os.Exit(1)
+		}
+	}
+
+	// make cache dir
+	if err := os.MkdirAll(ImageCacheDir, 0777); err != nil {
+		fmt.Printf("%q\n", err)
+		os.Exit(1)
+	}
+
+	podman.StartVarlink()
+	for _, image := range CACHE_IMAGES {
+		podman.createArtifact(image)
+	}
+	podman.StopVarlink()
+	// If running localized tests, the cache dir is created and populated. if the
+	// tests are remote, this is a no-op
+	populateCache(podman)
+
+	path, err := ioutil.TempDir("", "libpodlock")
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	return []byte(path)
+}, func(data []byte) {
+	LockTmpDir = string(data)
+})
+
+var _ = SynchronizedAfterSuite(func() {},
+	func() {
+		podman := Setup("/tmp")
+		if err := os.RemoveAll(podman.CrioRoot); err != nil {
+			fmt.Printf("%q\n", err)
+			os.Exit(1)
+		}
+		if err := os.RemoveAll(podman.ImageCacheDir); err != nil {
+			fmt.Printf("%q\n", err)
+			os.Exit(1)
+		}
+	})
diff --git a/test/endpoint/exists_test.go b/test/endpoint/exists_test.go
new file mode 100644
index 000000000..c8ab9e0f2
--- /dev/null
+++ b/test/endpoint/exists_test.go
@@ -0,0 +1,66 @@
+package endpoint
+
+import (
+	"os"
+
+	. "github.com/containers/libpod/test/utils"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman pull", func() {
+	var (
+		tempdir      string
+		err          error
+		endpointTest *EndpointTestIntegration
+	)
+
+	BeforeEach(func() {
+		tempdir, err = CreateTempDirInTempDir()
+		if err != nil {
+			os.Exit(1)
+		}
+		endpointTest = Setup(tempdir)
+		endpointTest.StartVarlinkWithCache()
+	})
+
+	AfterEach(func() {
+		endpointTest.Cleanup()
+		//f := CurrentGinkgoTestDescription()
+		//processTestResult(f)
+
+	})
+
+	It("image exists in local storage", func() {
+		result := endpointTest.Varlink("ImageExists", makeNameMessage(ALPINE), false)
+		Expect(result.ExitCode()).To(BeZero())
+
+		output := result.OutputToMapToInt()
+		Expect(output["exists"]).To(BeZero())
+	})
+
+	It("image exists in local storage by shortname", func() {
+		result := endpointTest.Varlink("ImageExists", makeNameMessage("alpine"), false)
+		Expect(result.ExitCode()).To(BeZero())
+
+		output := result.OutputToMapToInt()
+		Expect(output["exists"]).To(BeZero())
+	})
+
+	It("image does not exist in local storage", func() {
+		result := endpointTest.Varlink("ImageExists", makeNameMessage("alpineforest"), false)
+		Expect(result.ExitCode()).To(BeZero())
+
+		output := result.OutputToMapToInt()
+		Expect(output["exists"]).To(Equal(1))
+	})
+
+	It("container exists in local storage by name", func() {
+		_ = endpointTest.startTopContainer("top")
+		result := endpointTest.Varlink("ContainerExists", makeNameMessage("top"), false)
+		Expect(result.ExitCode()).To(BeZero())
+		output := result.OutputToMapToInt()
+		Expect(output["exists"]).To(BeZero())
+	})
+
+})
diff --git a/test/endpoint/pull_test.go b/test/endpoint/pull_test.go
new file mode 100644
index 000000000..51eb9c760
--- /dev/null
+++ b/test/endpoint/pull_test.go
@@ -0,0 +1,44 @@
+package endpoint
+
+import (
+	"os"
+
+	. "github.com/containers/libpod/test/utils"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman pull", func() {
+	var (
+		tempdir      string
+		err          error
+		endpointTest *EndpointTestIntegration
+	)
+
+	BeforeEach(func() {
+		tempdir, err = CreateTempDirInTempDir()
+		if err != nil {
+			os.Exit(1)
+		}
+		endpointTest = Setup(tempdir)
+		endpointTest.StartVarlink()
+	})
+
+	AfterEach(func() {
+		endpointTest.Cleanup()
+		//f := CurrentGinkgoTestDescription()
+		//processTestResult(f)
+
+	})
+
+	It("podman pull", func() {
+		session := endpointTest.Varlink("PullImage", makeNameMessage(ALPINE), false)
+		Expect(session.ExitCode()).To(BeZero())
+
+		result := endpointTest.Varlink("ImageExists", makeNameMessage(ALPINE), false)
+		Expect(result.ExitCode()).To(BeZero())
+
+		output := result.OutputToMapToInt()
+		Expect(output["exists"]).To(BeZero())
+	})
+})
diff --git a/test/endpoint/setup.go b/test/endpoint/setup.go
new file mode 100644
index 000000000..727f29ec6
--- /dev/null
+++ b/test/endpoint/setup.go
@@ -0,0 +1,219 @@
+package endpoint
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+
+	iopodman "github.com/containers/libpod/cmd/podman/varlink"
+	"github.com/containers/libpod/pkg/rootless"
+	"github.com/containers/storage/pkg/stringid"
+	"github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+	"github.com/sirupsen/logrus"
+)
+
+func Setup(tempDir string) *EndpointTestIntegration {
+	var (
+		endpoint string
+	)
+	cwd, _ := os.Getwd()
+	INTEGRATION_ROOT = filepath.Join(cwd, "../../")
+
+	podmanBinary := filepath.Join(cwd, "../../bin/podman")
+	if os.Getenv("PODMAN_BINARY") != "" {
+		podmanBinary = os.Getenv("PODMAN_BINARY")
+	}
+	conmonBinary := filepath.Join("/usr/libexec/podman/conmon")
+	altConmonBinary := "/usr/bin/conmon"
+	if _, err := os.Stat(conmonBinary); os.IsNotExist(err) {
+		conmonBinary = altConmonBinary
+	}
+	if os.Getenv("CONMON_BINARY") != "" {
+		conmonBinary = os.Getenv("CONMON_BINARY")
+	}
+	storageOptions := STORAGE_OPTIONS
+	if os.Getenv("STORAGE_OPTIONS") != "" {
+		storageOptions = os.Getenv("STORAGE_OPTIONS")
+	}
+	cgroupManager := CGROUP_MANAGER
+	if rootless.IsRootless() {
+		cgroupManager = "cgroupfs"
+	}
+	if os.Getenv("CGROUP_MANAGER") != "" {
+		cgroupManager = os.Getenv("CGROUP_MANAGER")
+	}
+
+	ociRuntime := os.Getenv("OCI_RUNTIME")
+	if ociRuntime == "" {
+		var err error
+		ociRuntime, err = exec.LookPath("runc")
+		// If we cannot find the runc binary, setting to something static as we have no way
+		// to return an error.  The tests will fail and point out that the runc binary could
+		// not be found nicely.
+		if err != nil {
+			ociRuntime = "/usr/bin/runc"
+		}
+	}
+	os.Setenv("DISABLE_HC_SYSTEMD", "true")
+	CNIConfigDir := "/etc/cni/net.d"
+
+	storageFs := STORAGE_FS
+	if rootless.IsRootless() {
+		storageFs = ROOTLESS_STORAGE_FS
+	}
+
+	uuid := stringid.GenerateNonCryptoID()
+	if !rootless.IsRootless() {
+		endpoint = fmt.Sprintf("unix:/run/podman/io.podman-%s", uuid)
+	} else {
+		runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+		socket := fmt.Sprintf("io.podman-%s", uuid)
+		fqpath := filepath.Join(runtimeDir, socket)
+		endpoint = fmt.Sprintf("unix:%s", fqpath)
+	}
+
+	eti := EndpointTestIntegration{
+		ArtifactPath:        ARTIFACT_DIR,
+		CNIConfigDir:        CNIConfigDir,
+		CgroupManager:       cgroupManager,
+		ConmonBinary:        conmonBinary,
+		CrioRoot:            filepath.Join(tempDir, "crio"),
+		ImageCacheDir:       ImageCacheDir,
+		ImageCacheFS:        storageFs,
+		OCIRuntime:          ociRuntime,
+		PodmanBinary:        podmanBinary,
+		RunRoot:             filepath.Join(tempDir, "crio-run"),
+		SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"),
+		StorageOptions:      storageOptions,
+		TmpDir:              tempDir,
+		//Timings:             nil,
+		VarlinkBinary:   VarlinkBinary,
+		VarlinkCommand:  nil,
+		VarlinkEndpoint: endpoint,
+		VarlinkSession:  nil,
+	}
+	return &eti
+}
+
+func (p *EndpointTestIntegration) Cleanup() {
+	// Remove all containers
+	// TODO Make methods to do all this?
+
+	p.stopAllContainers()
+
+	//TODO need to make stop all pods
+
+	p.StopVarlink()
+	// Nuke tempdir
+	if err := os.RemoveAll(p.TmpDir); err != nil {
+		fmt.Printf("%q\n", err)
+	}
+
+	// Clean up the registries configuration file ENV variable set in Create
+	resetRegistriesConfigEnv()
+}
+
+func (p *EndpointTestIntegration) listContainers() []iopodman.Container {
+	containers := p.Varlink("ListContainers", "", false)
+	var varlinkContainers map[string][]iopodman.Container
+	if err := json.Unmarshal(containers.OutputToBytes(), &varlinkContainers); err != nil {
+		logrus.Error("failed to unmarshal containers")
+	}
+	return varlinkContainers["containers"]
+}
+
+func (p *EndpointTestIntegration) stopAllContainers() {
+	containers := p.listContainers()
+	for _, container := range containers {
+		p.stopContainer(container.Id)
+	}
+}
+
+func (p *EndpointTestIntegration) stopContainer(cid string) {
+	p.Varlink("StopContainer", fmt.Sprintf("{\"name\":\"%s\", \"timeout\":0}", cid), false)
+}
+
+func resetRegistriesConfigEnv() {
+	os.Setenv("REGISTRIES_CONFIG_PATH", "")
+}
+
+func (p *EndpointTestIntegration) createArtifact(image string) {
+	if os.Getenv("NO_TEST_CACHE") != "" {
+		return
+	}
+	dest := strings.Split(image, "/")
+	destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
+	fmt.Printf("Caching %s at %s...", image, destName)
+	if _, err := os.Stat(destName); os.IsNotExist(err) {
+		pull := p.Varlink("PullImage", fmt.Sprintf("{\"name\":\"%s\"}", image), false)
+		Expect(pull.ExitCode()).To(Equal(0))
+
+		imageSave := iopodman.ImageSaveOptions{
+			//Name:image,
+			//Output: destName,
+			//Format: "oci-archive",
+		}
+		imageSave.Name = image
+		imageSave.Output = destName
+		imageSave.Format = "oci-archive"
+		foo := make(map[string]iopodman.ImageSaveOptions)
+		foo["options"] = imageSave
+		f, _ := json.Marshal(foo)
+		save := p.Varlink("ImageSave", string(f), false)
+		result := save.OutputToMoreResponse()
+		Expect(save.ExitCode()).To(Equal(0))
+		Expect(os.Rename(result.Id, destName)).To(BeNil())
+		fmt.Printf("\n")
+	} else {
+		fmt.Printf(" already exists.\n")
+	}
+}
+
+func populateCache(p *EndpointTestIntegration) {
+	p.CrioRoot = p.ImageCacheDir
+	p.StartVarlink()
+	for _, image := range CACHE_IMAGES {
+		p.RestoreArtifactToCache(image)
+	}
+	p.StopVarlink()
+}
+
+func (p *EndpointTestIntegration) RestoreArtifactToCache(image string) error {
+	fmt.Printf("Restoring %s...\n", image)
+	dest := strings.Split(image, "/")
+	destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
+	//fmt.Println(destName, p.ImageCacheDir)
+	load := p.Varlink("LoadImage", fmt.Sprintf("{\"name\": \"%s\", \"inputFile\": \"%s\"}", image, destName), false)
+	Expect(load.ExitCode()).To(BeZero())
+	return nil
+}
+
+func (p *EndpointTestIntegration) startTopContainer(name string) string {
+	t := true
+	args := iopodman.Create{
+		Args:   []string{"docker.io/library/alpine:latest", "top"},
+		Tty:    &t,
+		Detach: &t,
+	}
+	if len(name) > 0 {
+		args.Name = &name
+	}
+	b, err := json.Marshal(args)
+	if err != nil {
+		ginkgo.Fail("failed to marshal data for top container")
+	}
+	input := fmt.Sprintf("{\"create\":%s}", string(b))
+	top := p.Varlink("CreateContainer", input, false)
+	if top.ExitCode() != 0 {
+		ginkgo.Fail("failed to start top container")
+	}
+	start := p.Varlink("StartContainer", fmt.Sprintf("{\"name\":\"%s\"}", name), false)
+	if start.ExitCode() != 0 {
+		ginkgo.Fail("failed to start top container")
+	}
+	return start.OutputToString()
+}
diff --git a/test/endpoint/version_test.go b/test/endpoint/version_test.go
new file mode 100644
index 000000000..a1168da70
--- /dev/null
+++ b/test/endpoint/version_test.go
@@ -0,0 +1,41 @@
+package endpoint
+
+import (
+	"os"
+
+	. "github.com/containers/libpod/test/utils"
+	"github.com/containers/libpod/version"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman version", func() {
+	var (
+		tempdir      string
+		err          error
+		endpointTest *EndpointTestIntegration
+	)
+
+	BeforeEach(func() {
+		tempdir, err = CreateTempDirInTempDir()
+		if err != nil {
+			os.Exit(1)
+		}
+		endpointTest = Setup(tempdir)
+		endpointTest.StartVarlink()
+	})
+
+	AfterEach(func() {
+		endpointTest.Cleanup()
+		//f := CurrentGinkgoTestDescription()
+		//processTestResult(f)
+
+	})
+
+	It("podman version", func() {
+		session := endpointTest.Varlink("GetVersion", "", false)
+		result := session.OutputToStringMap()
+		Expect(result["version"]).To(Equal(version.Version))
+		Expect(session.ExitCode()).To(Equal(0))
+	})
+})
-- 
cgit v1.2.3-54-g00ecf