summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--cmd/podman/cp.go9
-rw-r--r--docs/tutorials/podman_tutorial.md12
-rw-r--r--pkg/registrar/registrar_test.go318
-rw-r--r--test/e2e/cp_test.go33
-rw-r--r--test/framework/framework.go56
6 files changed, 318 insertions, 119 deletions
diff --git a/Makefile b/Makefile
index 1f4a7f6e7..ebd0ddf2d 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,6 @@ BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
ZSHINSTALLDIR=${PREFIX}/share/zsh/site-functions
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
-PACKAGES ?= $(shell $(GO) list -tags "${BUILDTAGS}" ./... | grep -v github.com/containers/libpod/vendor | grep -v e2e | grep -v system )
COMMIT_NO ?= $(shell git rev-parse HEAD 2> /dev/null || true)
GIT_COMMIT ?= $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO})
@@ -172,7 +171,13 @@ testunit: libpodimage ## Run unittest on the built image
${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e OCI_RUNTIME -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make localunit
localunit: test/goecho/goecho varlink_generate
- $(GO) test -tags "$(BUILDTAGS)" -cover $(PACKAGES)
+ ginkgo \
+ -r \
+ --skipPackage test/e2e,pkg/apparmor \
+ --cover \
+ --covermode atomic \
+ --tags "$(BUILDTAGS)" \
+ --succinct
$(MAKE) -C contrib/cirrus/packer test
ginkgo:
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index a0dd46260..7dee37287 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"os"
"path/filepath"
"strings"
@@ -207,6 +208,11 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
if !srcfi.IsDir() && !strings.HasSuffix(dest, string(os.PathSeparator)) {
destdir = filepath.Dir(destPath)
}
+ _, err = os.Stat(destdir)
+ if err != nil && !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error checking directory %q", destdir)
+ }
+ destDirIsExist := (err == nil)
if err = os.MkdirAll(destdir, 0755); err != nil {
return errors.Wrapf(err, "error creating directory %q", destdir)
}
@@ -219,6 +225,9 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
if srcfi.IsDir() {
logrus.Debugf("copying %q to %q", srcPath+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*")
+ if destDirIsExist && !strings.HasSuffix(src, fmt.Sprintf("%s.", string(os.PathSeparator))) {
+ destPath = filepath.Join(destPath, filepath.Base(srcPath))
+ }
if err = copyWithTar(srcPath, destPath); err != nil {
return errors.Wrapf(err, "error copying %q to %q", srcPath, dest)
}
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index bfff90016..2abd9c50f 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -123,13 +123,14 @@ sudo make install PREFIX=/usr
This sample container will run a very basic httpd server that serves only its index
page.
```console
-podman run -dt -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \
+podman run -dt -p 8080:8080/tcp -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CONF_D_PATH=/etc/httpd/conf.d \
-e HTTPD_MAIN_CONF_PATH=/etc/httpd/conf \
-e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \
registry.fedoraproject.org/f27/httpd /usr/bin/run-httpd
```
Because the container is being run in detached mode, represented by the *-d* in the podman run command, podman
-will print the container ID after it has run.
+will print the container ID after it has run. Note that we use port forwarding to be able to
+access the HTTP server. For successful running at least slirp4netns v0.3.0 is needed.
### Listing running containers
The Podman *ps* command is used to list creating and running containers.
@@ -140,10 +141,11 @@ podman ps
Note: If you add *-a* to the *ps* command, Podman will show all containers.
### Inspecting a running container
You can "inspect" a running container for metadata and details about itself. We can even use
-the inspect subcommand to see what IP address was assigned to the container.
+the inspect subcommand to see what IP address was assigned to the container. As the container is running in rootless mode, an IP address is not assigned and the value will be listed as "none" in the output from inspect.
```console
-$ sudo podman inspect -l | grep IPAddress\":
- "IPAddress": "10.88.6.140",
+$ podman inspect -l | grep IPAddress\":
+ "SecondaryIPAddresses": null,
+ "IPAddress": "",
```
Note: The -l is a convenience argument for **latest container**. You can also use the container's ID instead
diff --git a/pkg/registrar/registrar_test.go b/pkg/registrar/registrar_test.go
index 0c1ef312a..50af95915 100644
--- a/pkg/registrar/registrar_test.go
+++ b/pkg/registrar/registrar_test.go
@@ -1,119 +1,213 @@
-package registrar
+package registrar_test
import (
- "reflect"
"testing"
-)
-
-func TestReserve(t *testing.T) {
- r := NewRegistrar()
-
- obj := "test1"
- if err := r.Reserve("test", obj); err != nil {
- t.Fatal(err)
- }
-
- if err := r.Reserve("test", obj); err != nil {
- t.Fatal(err)
- }
-
- obj2 := "test2"
- err := r.Reserve("test", obj2)
- if err == nil {
- t.Fatalf("expected error when reserving an already reserved name to another object")
- }
- if err != ErrNameReserved {
- t.Fatal("expected `ErrNameReserved` error when attempting to reserve an already reserved name")
- }
-}
-
-func TestRelease(t *testing.T) {
- r := NewRegistrar()
- obj := "testing"
-
- if err := r.Reserve("test", obj); err != nil {
- t.Fatal(err)
- }
- r.Release("test")
- r.Release("test") // Ensure there is no panic here
- if err := r.Reserve("test", obj); err != nil {
- t.Fatal(err)
- }
-}
-
-func TestGetNames(t *testing.T) {
- r := NewRegistrar()
- obj := "testing"
- names := []string{"test1", "test2"}
-
- for _, name := range names {
- if err := r.Reserve(name, obj); err != nil {
- t.Fatal(err)
- }
- }
- r.Reserve("test3", "other")
-
- names2, err := r.GetNames(obj)
- if err != nil {
- t.Fatal(err)
- }
-
- if !reflect.DeepEqual(names, names2) {
- t.Fatalf("Exepected: %v, Got: %v", names, names2)
- }
-}
+ "github.com/containers/libpod/pkg/registrar"
+ . "github.com/containers/libpod/test/framework"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
-func TestDelete(t *testing.T) {
- r := NewRegistrar()
- obj := "testing"
- names := []string{"test1", "test2"}
- for _, name := range names {
- if err := r.Reserve(name, obj); err != nil {
- t.Fatal(err)
- }
- }
-
- r.Reserve("test3", "other")
- r.Delete(obj)
-
- _, err := r.GetNames(obj)
- if err == nil {
- t.Fatal("expected error getting names for deleted key")
- }
-
- if err != ErrNoSuchKey {
- t.Fatal("expected `ErrNoSuchKey`")
- }
+// TestRegistrar runs the created specs
+func TestRegistrar(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Registrar")
}
-func TestGet(t *testing.T) {
- r := NewRegistrar()
- obj := "testing"
- name := "test"
-
- _, err := r.Get(name)
- if err == nil {
- t.Fatal("expected error when key does not exist")
- }
- if err != ErrNameNotReserved {
- t.Fatal(err)
- }
-
- if err := r.Reserve(name, obj); err != nil {
- t.Fatal(err)
- }
-
- if _, err = r.Get(name); err != nil {
- t.Fatal(err)
- }
-
- r.Delete(obj)
- _, err = r.Get(name)
- if err == nil {
- t.Fatal("expected error when key does not exist")
- }
- if err != ErrNameNotReserved {
- t.Fatal(err)
- }
-}
+// nolint: gochecknoglobals
+var t *TestFramework
+
+var _ = BeforeSuite(func() {
+ t = NewTestFramework(NilFunc, NilFunc)
+ t.Setup()
+})
+
+var _ = AfterSuite(func() {
+ t.Teardown()
+})
+
+// The actual test suite
+var _ = t.Describe("Registrar", func() {
+ // Constant test data needed by some tests
+ const (
+ testKey = "testKey"
+ testName = "testName"
+ anotherKey = "anotherKey"
+ )
+
+ // The system under test
+ var sut *registrar.Registrar
+
+ // Prepare the system under test and register a test name and key before
+ // each test
+ BeforeEach(func() {
+ sut = registrar.NewRegistrar()
+ Expect(sut.Reserve(testName, testKey)).To(BeNil())
+ })
+
+ t.Describe("Reserve", func() {
+ It("should succeed to reserve a new registrar", func() {
+ // Given
+ // When
+ err := sut.Reserve("name", "key")
+
+ // Then
+ Expect(err).To(BeNil())
+ })
+
+ It("should succeed to reserve a registrar twice", func() {
+ // Given
+ // When
+ err := sut.Reserve(testName, testKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ })
+
+ It("should fail to reserve an already reserved registrar", func() {
+ // Given
+ // When
+ err := sut.Reserve(testName, anotherKey)
+
+ // Then
+ Expect(err).NotTo(BeNil())
+ Expect(err).To(Equal(registrar.ErrNameReserved))
+ })
+ })
+
+ t.Describe("Release", func() {
+ It("should succeed to release a registered registrar multiple times", func() {
+ // Given
+ // When
+ // Then
+ sut.Release(testName)
+ sut.Release(testName)
+ })
+
+ It("should succeed to release a unknown registrar multiple times", func() {
+ // Given
+ // When
+ // Then
+ sut.Release(anotherKey)
+ sut.Release(anotherKey)
+ })
+
+ It("should succeed to release and re-register a registrar", func() {
+ // Given
+ // When
+ sut.Release(testName)
+ err := sut.Reserve(testName, testKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ })
+ })
+
+ t.Describe("GetNames", func() {
+ It("should succeed to retrieve a single name for a registrar", func() {
+ // Given
+ // When
+ names, err := sut.GetNames(testKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ Expect(len(names)).To(Equal(1))
+ Expect(names[0]).To(Equal(testName))
+ })
+
+ It("should succeed to retrieve all names for a registrar", func() {
+ // Given
+ testNames := []string{"test1", "test2"}
+ for _, name := range testNames {
+ Expect(sut.Reserve(name, anotherKey)).To(BeNil())
+ }
+
+ // When
+ names, err := sut.GetNames(anotherKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ Expect(len(names)).To(Equal(2))
+ Expect(names).To(Equal(testNames))
+ })
+ })
+
+ t.Describe("GetNames", func() {
+ It("should succeed to retrieve a single name for a registrar", func() {
+ // Given
+ // When
+ names, err := sut.GetNames(testKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ Expect(len(names)).To(Equal(1))
+ Expect(names[0]).To(Equal(testName))
+ })
+
+ It("should succeed to retrieve all names for a registrar", func() {
+ // Given
+ anotherKey := "anotherKey"
+ testNames := []string{"test1", "test2"}
+ for _, name := range testNames {
+ Expect(sut.Reserve(name, anotherKey)).To(BeNil())
+ }
+
+ // When
+ names, err := sut.GetNames(anotherKey)
+
+ // Then
+ Expect(err).To(BeNil())
+ Expect(len(names)).To(Equal(2))
+ Expect(names).To(Equal(testNames))
+ })
+ })
+
+ t.Describe("Delete", func() {
+ It("should succeed to delete a registrar", func() {
+ // Given
+ // When
+ sut.Delete(testKey)
+
+ // Then
+ names, err := sut.GetNames(testKey)
+ Expect(len(names)).To(BeZero())
+ Expect(err).To(Equal(registrar.ErrNoSuchKey))
+ })
+ })
+
+ t.Describe("Get", func() {
+ It("should succeed to get a key for a registrar", func() {
+ // Given
+ // When
+ key, err := sut.Get(testName)
+
+ // Then
+ Expect(err).To(BeNil())
+ Expect(key).To(Equal(testKey))
+ })
+
+ It("should fail to get a key for a not existing registrar", func() {
+ // Given
+ // When
+ key, err := sut.Get("notExistingName")
+
+ // Then
+ Expect(key).To(BeEmpty())
+ Expect(err).To(Equal(registrar.ErrNameNotReserved))
+ })
+ })
+
+ t.Describe("GetAll", func() {
+ It("should succeed to get all names", func() {
+ // Given
+ // When
+ names := sut.GetAll()
+
+ // Then
+ Expect(len(names)).To(Equal(1))
+ Expect(len(names[testKey])).To(Equal(1))
+ Expect(names[testKey][0]).To(Equal(testName))
+ })
+ })
+})
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index f89865264..591f533d6 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -112,4 +112,37 @@ var _ = Describe("Podman cp", func() {
}
Expect(string(output)).To(Equal("copy from host to container directory"))
})
+
+ It("podman cp dir to dir", func() {
+ path, err := os.Getwd()
+ if err != nil {
+ os.Exit(1)
+ }
+ testDirPath := filepath.Join(path, "TestDir")
+ err = os.Mkdir(testDirPath, 0777)
+ if err != nil {
+ os.Exit(1)
+ }
+
+ session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ name := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"start", "-a", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"start", "-a", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(Equal("TestDir"))
+ })
})
diff --git a/test/framework/framework.go b/test/framework/framework.go
new file mode 100644
index 000000000..52401faf8
--- /dev/null
+++ b/test/framework/framework.go
@@ -0,0 +1,56 @@
+package framework
+
+import (
+ "fmt"
+
+ "github.com/onsi/ginkgo"
+ "github.com/onsi/gomega"
+)
+
+// TestFramework is used to support commonnly used test features
+type TestFramework struct {
+ setup func(*TestFramework) error
+ teardown func(*TestFramework) error
+ TestError error
+}
+
+// NewTestFramework creates a new test framework instance for a given `setup`
+// and `teardown` function
+func NewTestFramework(
+ setup func(*TestFramework) error,
+ teardown func(*TestFramework) error,
+) *TestFramework {
+ return &TestFramework{
+ setup,
+ teardown,
+ fmt.Errorf("error"),
+ }
+}
+
+// NilFn is a convenience function which simply does nothing
+func NilFunc(f *TestFramework) error {
+ return nil
+}
+
+// Setup is the global initialization function which runs before each test
+// suite
+func (t *TestFramework) Setup() {
+ // Global initialization for the whole framework goes in here
+
+ // Setup the actual test suite
+ gomega.Expect(t.setup(t)).To(gomega.Succeed())
+}
+
+// Teardown is the global deinitialization function which runs after each test
+// suite
+func (t *TestFramework) Teardown() {
+ // Global deinitialization for the whole framework goes in here
+
+ // Teardown the actual test suite
+ gomega.Expect(t.teardown(t)).To(gomega.Succeed())
+}
+
+// Describe is a convenience wrapper around the `ginkgo.Describe` function
+func (t *TestFramework) Describe(text string, body func()) bool {
+ return ginkgo.Describe("libpod: "+text, body)
+}