diff --git a/integration/check_test.go b/integration/check_test.go index 67e8fc61..abaaf012 100644 --- a/integration/check_test.go +++ b/integration/check_test.go @@ -3,7 +3,6 @@ package main import ( "fmt" "os/exec" - "strings" "testing" "github.com/go-check/check" @@ -15,8 +14,6 @@ const ( privateRegistryURL2 = "127.0.0.1:5002" privateRegistryURL3 = "127.0.0.1:5003" privateRegistryURL4 = "127.0.0.1:5004" - - skopeoBinary = "skopeo" ) func Test(t *testing.T) { @@ -73,38 +70,26 @@ func (s *SkopeoSuite) TearDownTest(c *check.C) { //func skopeoCmd() func (s *SkopeoSuite) TestVersion(c *check.C) { - out, err := exec.Command(skopeoBinary, "--version").CombinedOutput() - c.Assert(err, check.IsNil, check.Commentf(string(out))) - wanted := skopeoBinary + " version " - if !strings.Contains(string(out), wanted) { - c.Fatalf("wanted %s, got %s", wanted, string(out)) - } + wanted := fmt.Sprintf(".*%s version .*", skopeoBinary) + assertSkopeoSucceeds(c, wanted, "--version") } -var ( - errFetchManifest = "error fetching manifest: status code: %s" +const ( + errFetchManifestRegexp = ".*error fetching manifest: status code: %s.*" ) func (s *SkopeoSuite) TestCanAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) { // TODO(runcom) 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() - c.Assert(err, check.NotNil, check.Commentf(string(out))) - wanted := fmt.Sprintf(errFetchManifest, "401") - if !strings.Contains(string(out), wanted) { - c.Fatalf("wanted %s, got %s", wanted, string(out)) - } + wanted := fmt.Sprintf(errFetchManifestRegexp, "401") + assertSkopeoFails(c, wanted, "--docker-cfg=''", "--username="+s.regV2WithAuth.username, "--password="+s.regV2WithAuth.password, "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url)) } func (s *SkopeoSuite) TestNeedAuthToPrivateRegistryV2WithoutDockerCfg(c *check.C) { // TODO(runcom): mock the empty docker-cfg by removing it in the test itself (?) c.Skip("mock empty docker config") - out, err := exec.Command(skopeoBinary, "--docker-cfg=''", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url)).CombinedOutput() - c.Assert(err, check.NotNil, check.Commentf(string(out))) - wanted := fmt.Sprintf(errFetchManifest, "401") - if !strings.Contains(string(out), wanted) { - c.Fatalf("wanted %s, got %s", wanted, string(out)) - } + wanted := fmt.Sprintf(errFetchManifestRegexp, "401") + assertSkopeoFails(c, wanted, "--docker-cfg=''", "inspect", fmt.Sprintf("docker://%s/busybox:latest", s.regV2WithAuth.url)) } // 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) { 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))) - wanted := fmt.Sprintf(errFetchManifest, "404") - if !strings.Contains(string(out), wanted) { - c.Fatalf("wanted %s, got %s", wanted, string(out)) - } - wanted = fmt.Sprintf(errFetchManifest, "401") - if strings.Contains(string(out), wanted) { - c.Fatalf("not wanted %s, got %s", wanted, string(out)) - } + wanted := fmt.Sprintf(errFetchManifestRegexp, "404") + c.Assert(string(out), check.Matches, "(?s)"+wanted) // (?s) : '.' will also match newlines + wanted = fmt.Sprintf(errFetchManifestRegexp, "401") + c.Assert(string(out), check.Not(check.Matches), "(?s)"+wanted) // (?s) : '.' will also match newlines } diff --git a/integration/signing_test.go b/integration/signing_test.go index fa8a15e8..6ea1e308 100644 --- a/integration/signing_test.go +++ b/integration/signing_test.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "io/ioutil" "os" "os/exec" @@ -42,21 +43,7 @@ func (s *SigningSuite) SetUpTest(c *check.C) { c.Assert(err, check.IsNil) os.Setenv("GNUPGHOME", s.gpgHome) - cmd := exec.Command(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) + runCommandWithInput(c, "Key-Type: RSA\nName-Real: Testing user\n%commit\n", gpgBinary, "--homedir", s.gpgHome, "--batch", "--gen-key") lines, err := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--with-colons", "--no-permission-warning", "--fingerprint").Output() c.Assert(err, check.IsNil) @@ -81,13 +68,10 @@ func (s *SigningSuite) TestSignVerifySmoke(c *check.C) { sigOutput, err := ioutil.TempFile("", "sig") c.Assert(err, check.IsNil) defer os.Remove(sigOutput.Name()) - out, err := exec.Command(skopeoBinary, "standalone-sign", "-o", sigOutput.Name(), - manifestPath, dockerReference, s.fingerprint).CombinedOutput() - c.Assert(err, check.IsNil, check.Commentf("%s", out)) - c.Assert(string(out), check.Equals, "") + assertSkopeoSucceeds(c, "^$", "standalone-sign", "-o", sigOutput.Name(), + manifestPath, dockerReference, s.fingerprint) - out, err = exec.Command(skopeoBinary, "standalone-verify", manifestPath, - dockerReference, s.fingerprint, sigOutput.Name()).CombinedOutput() - c.Assert(err, check.IsNil, check.Commentf("%s", out)) - c.Assert(string(out), check.Equals, "Signature verified, digest "+TestImageManifestDigest+"\n") + expected := fmt.Sprintf("^Signature verified, digest %s\n$", TestImageManifestDigest) + assertSkopeoSucceeds(c, expected, "standalone-verify", manifestPath, + dockerReference, s.fingerprint, sigOutput.Name()) } diff --git a/integration/utils.go b/integration/utils.go index 3dd6f552..3f959db9 100644 --- a/integration/utils.go +++ b/integration/utils.go @@ -2,13 +2,16 @@ package main import ( "io" + "os/exec" "strings" "github.com/go-check/check" ) -// consumeAndLogOutput takes (f, err) from an exec.*Pipe(), and causes all output to it to be logged to c. -func consumeAndLogOutput(c *check.C, id string, f io.ReadCloser, err error) { +const skopeoBinary = "skopeo" + +// 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) go 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) +}