Add more helpers for running skopeo, use them in existing tests

- consumeAndLogOutputs
- assertSkopeoSucceeds
- assertSkopeoFails
- runCommandWithInput
All of these allow running commands as one-liners with no call-site
error handling, making tests much more readable.

Also modifies TestNoNeedAuthToPrivateRegistryV2ImageNotFound to use
check.Matches instead of manual strings.Contains conditions, which is
shorter and more consistent with the assertSkopeo... calls.
This commit is contained in:
Miloslav Trmač
2016-06-22 15:34:24 +02:00
parent 601f76f96d
commit 39b06cb31c
3 changed files with 72 additions and 56 deletions

View File

@@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"os/exec" "os/exec"
"strings"
"testing" "testing"
"github.com/go-check/check" "github.com/go-check/check"
@@ -15,8 +14,6 @@ const (
privateRegistryURL2 = "127.0.0.1:5002" privateRegistryURL2 = "127.0.0.1:5002"
privateRegistryURL3 = "127.0.0.1:5003" privateRegistryURL3 = "127.0.0.1:5003"
privateRegistryURL4 = "127.0.0.1:5004" privateRegistryURL4 = "127.0.0.1:5004"
skopeoBinary = "skopeo"
) )
func Test(t *testing.T) { func Test(t *testing.T) {
@@ -73,38 +70,26 @@ func (s *SkopeoSuite) TearDownTest(c *check.C) {
//func skopeoCmd() //func skopeoCmd()
func (s *SkopeoSuite) TestVersion(c *check.C) { func (s *SkopeoSuite) TestVersion(c *check.C) {
out, err := exec.Command(skopeoBinary, "--version").CombinedOutput() wanted := fmt.Sprintf(".*%s version .*", skopeoBinary)
c.Assert(err, check.IsNil, check.Commentf(string(out))) assertSkopeoSucceeds(c, wanted, "--version")
wanted := skopeoBinary + " version "
if !strings.Contains(string(out), wanted) {
c.Fatalf("wanted %s, got %s", wanted, string(out))
}
} }
var ( const (
errFetchManifest = "error fetching manifest: status code: %s" errFetchManifestRegexp = ".*error fetching manifest: status code: %s.*"
) )
func (s *SkopeoSuite) TestCanAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) { func (s *SkopeoSuite) TestCanAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) {
// TODO(runcom) // TODO(runcom)
c.Skip("we need to restore --username --password flags!") c.Skip("we need to restore --username --password flags!")
out, err := exec.Command(skopeoBinary, "--docker-cfg=''", "--username="+s.regV2WithAuth.username, "--password="+s.regV2WithAuth.password, "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url)).CombinedOutput() wanted := fmt.Sprintf(errFetchManifestRegexp, "401")
c.Assert(err, check.NotNil, check.Commentf(string(out))) assertSkopeoFails(c, wanted, "--docker-cfg=''", "--username="+s.regV2WithAuth.username, "--password="+s.regV2WithAuth.password, "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
wanted := fmt.Sprintf(errFetchManifest, "401")
if !strings.Contains(string(out), wanted) {
c.Fatalf("wanted %s, got %s", wanted, string(out))
}
} }
func (s *SkopeoSuite) TestNeedAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) { func (s *SkopeoSuite) TestNeedAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) {
// TODO(runcom): mock the empty docker-cfg by removing it in the test itself (?) // TODO(runcom): mock the empty docker-cfg by removing it in the test itself (?)
c.Skip("mock empty docker config") c.Skip("mock empty docker config")
out, err := exec.Command(skopeoBinary, "--docker-cfg=''", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url)).CombinedOutput() wanted := fmt.Sprintf(errFetchManifestRegexp, "401")
c.Assert(err, check.NotNil, check.Commentf(string(out))) assertSkopeoFails(c, wanted, "--docker-cfg=''", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url))
wanted := fmt.Sprintf(errFetchManifest, "401")
if !strings.Contains(string(out), wanted) {
c.Fatalf("wanted %s, got %s", wanted, string(out))
}
} }
// TODO(runcom): as soon as we can push to registries ensure you can inspect here // TODO(runcom): as soon as we can push to registries ensure you can inspect here
@@ -112,12 +97,8 @@ func (s *SkopeoSuite) TestNeedAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C
func (s *SkopeoSuite) TestNoNeedAuthToPrivateRegistryV2ImageNotFound(c *check.C) { func (s *SkopeoSuite) TestNoNeedAuthToPrivateRegistryV2ImageNotFound(c *check.C) {
out, err := exec.Command(skopeoBinary, "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2.url)).CombinedOutput() out, err := exec.Command(skopeoBinary, "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2.url)).CombinedOutput()
c.Assert(err, check.NotNil, check.Commentf(string(out))) c.Assert(err, check.NotNil, check.Commentf(string(out)))
wanted := fmt.Sprintf(errFetchManifest, "404") wanted := fmt.Sprintf(errFetchManifestRegexp, "404")
if !strings.Contains(string(out), wanted) { c.Assert(string(out), check.Matches, "(?s)"+wanted) // (?s) : '.' will also match newlines
c.Fatalf("wanted %s, got %s", wanted, string(out)) wanted = fmt.Sprintf(errFetchManifestRegexp, "401")
} c.Assert(string(out), check.Not(check.Matches), "(?s)"+wanted) // (?s) : '.' will also match newlines
wanted = fmt.Sprintf(errFetchManifest, "401")
if strings.Contains(string(out), wanted) {
c.Fatalf("not wanted %s, got %s", wanted, string(out))
}
} }

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@@ -42,21 +43,7 @@ func (s *SigningSuite) SetUpTest(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
os.Setenv("GNUPGHOME", s.gpgHome) os.Setenv("GNUPGHOME", s.gpgHome)
cmd := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--batch", "--gen-key") runCommandWithInput(c, "Key-Type: RSA\nName-Real: Testing user\n%commit\n", gpgBinary, "--homedir", s.gpgHome, "--batch", "--gen-key")
stdin, err := cmd.StdinPipe()
c.Assert(err, check.IsNil)
stdout, err := cmd.StdoutPipe()
consumeAndLogOutput(c, "gen-key stdout", stdout, err)
stderr, err := cmd.StderrPipe()
consumeAndLogOutput(c, "gen-key stderr", stderr, err)
err = cmd.Start()
c.Assert(err, check.IsNil)
_, err = stdin.Write([]byte("Key-Type: RSA\nName-Real: Testing user\n%commit\n"))
c.Assert(err, check.IsNil)
err = stdin.Close()
c.Assert(err, check.IsNil)
err = cmd.Wait()
c.Assert(err, check.IsNil)
lines, err := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--with-colons", "--no-permission-warning", "--fingerprint").Output() lines, err := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--with-colons", "--no-permission-warning", "--fingerprint").Output()
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
@@ -81,13 +68,10 @@ func (s *SigningSuite) TestSignVerifySmoke(c *check.C) {
sigOutput, err := ioutil.TempFile("", "sig") sigOutput, err := ioutil.TempFile("", "sig")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
defer os.Remove(sigOutput.Name()) defer os.Remove(sigOutput.Name())
out, err := exec.Command(skopeoBinary, "standalone-sign", "-o", sigOutput.Name(), assertSkopeoSucceeds(c, "^$", "standalone-sign", "-o", sigOutput.Name(),
manifestPath, dockerReference, s.fingerprint).CombinedOutput() manifestPath, dockerReference, s.fingerprint)
c.Assert(err, check.IsNil, check.Commentf("%s", out))
c.Assert(string(out), check.Equals, "")
out, err = exec.Command(skopeoBinary, "standalone-verify", manifestPath, expected := fmt.Sprintf("^Signature verified, digest %s\n$", TestImageManifestDigest)
dockerReference, s.fingerprint, sigOutput.Name()).CombinedOutput() assertSkopeoSucceeds(c, expected, "standalone-verify", manifestPath,
c.Assert(err, check.IsNil, check.Commentf("%s", out)) dockerReference, s.fingerprint, sigOutput.Name())
c.Assert(string(out), check.Equals, "Signature verified, digest "+TestImageManifestDigest+"\n")
} }

View File

@@ -2,13 +2,16 @@ package main
import ( import (
"io" "io"
"os/exec"
"strings" "strings"
"github.com/go-check/check" "github.com/go-check/check"
) )
// consumeAndLogOutput takes (f, err) from an exec.*Pipe(), and causes all output to it to be logged to c. const skopeoBinary = "skopeo"
func consumeAndLogOutput(c *check.C, id string, f io.ReadCloser, err error) {
// consumeAndLogOutputStream takes (f, err) from an exec.*Pipe(), and causes all output to it to be logged to c.
func consumeAndLogOutputStream(c *check.C, id string, f io.ReadCloser, err error) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
go func() { go func() {
defer func() { defer func() {
@@ -26,3 +29,51 @@ func consumeAndLogOutput(c *check.C, id string, f io.ReadCloser, err error) {
} }
}() }()
} }
// consumeAndLogOutputs causes all output to stdout and stderr from an *exec.Cmd to be logged to c
func consumeAndLogOutputs(c *check.C, id string, cmd *exec.Cmd) {
stdout, err := cmd.StdoutPipe()
consumeAndLogOutputStream(c, id+" stdout", stdout, err)
stderr, err := cmd.StderrPipe()
consumeAndLogOutputStream(c, id+" stderr", stderr, err)
}
// assertSkopeoSucceeds runs a skopeo command as if exec.Command().CombinedOutput, verifies that the exit status is 0,
// and optionally that the output matches a multi-line regexp if it is nonempty;
// or terminates c on failure
func assertSkopeoSucceeds(c *check.C, regexp string, args ...string) {
c.Logf("Running %s %s", skopeoBinary, strings.Join(args, " "))
out, err := exec.Command(skopeoBinary, args...).CombinedOutput()
c.Assert(err, check.IsNil, check.Commentf("%s", out))
if regexp != "" {
c.Assert(string(out), check.Matches, "(?s)"+regexp) // (?s) : '.' will also match newlines
}
}
// assertSkopeoFails runs a skopeo command as if exec.Command().CombinedOutput, verifies that the exit status is 0,
// and that the output matches a multi-line regexp;
// or terminates c on failure
func assertSkopeoFails(c *check.C, regexp string, args ...string) {
c.Logf("Running %s %s", skopeoBinary, strings.Join(args, " "))
out, err := exec.Command(skopeoBinary, args...).CombinedOutput()
c.Assert(err, check.NotNil, check.Commentf("%s", out))
c.Assert(string(out), check.Matches, "(?s)"+regexp) // (?s) : '.' will also match newlines
}
// runCommandWithInput runs a command as if exec.Command(), sending it the input to stdin,
// and verifies that the exit status is 0, or terminates c on failure.
func runCommandWithInput(c *check.C, input string, name string, args ...string) {
c.Logf("Running %s %s", name, strings.Join(args, " "))
cmd := exec.Command(name, args...)
consumeAndLogOutputs(c, name+" "+strings.Join(args, " "), cmd)
stdin, err := cmd.StdinPipe()
c.Assert(err, check.IsNil)
err = cmd.Start()
c.Assert(err, check.IsNil)
_, err = stdin.Write([]byte(input))
c.Assert(err, check.IsNil)
err = stdin.Close()
c.Assert(err, check.IsNil)
err = cmd.Wait()
c.Assert(err, check.IsNil)
}