Skip to content

Commit

Permalink
BeAvailable prints container logs when it fails
Browse files Browse the repository at this point in the history
Resolves #20
  • Loading branch information
Ryan Moran authored and joshzarrabi committed Jun 1, 2020
1 parent bbc8ed2 commit 49f9b28
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 6 deletions.
29 changes: 23 additions & 6 deletions matchers/be_available.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import (
)

func BeAvailable() types.GomegaMatcher {
return &BeAvailableMatcher{}
return &BeAvailableMatcher{
Docker: occam.NewDocker(),
}
}

type BeAvailableMatcher struct {
Docker occam.Docker
}

func (*BeAvailableMatcher) Match(actual interface{}) (bool, error) {
Expand All @@ -23,18 +26,32 @@ func (*BeAvailableMatcher) Match(actual interface{}) (bool, error) {

response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort()))
if err != nil {
return false, err
return false, nil
}

defer response.Body.Close()

return true, nil
}

func (*BeAvailableMatcher) FailureMessage(actual interface{}) string {
return fmt.Sprintf("Expected\n\t%#v\nto be available", actual)
func (m *BeAvailableMatcher) FailureMessage(actual interface{}) string {
container := actual.(occam.Container)
message := fmt.Sprintf("Expected\n\tdocker container id: %s\nto be available.", container.ID)

if logs, _ := m.Docker.Container.Logs.Execute(container.ID); logs != nil {
message = fmt.Sprintf("%s\n\nContainer logs:\n\n%s", message, logs)
}

return message
}

func (*BeAvailableMatcher) NegatedFailureMessage(actual interface{}) string {
return fmt.Sprintf("Expected\n\t%#v\nnot to be available", actual)
func (m *BeAvailableMatcher) NegatedFailureMessage(actual interface{}) string {
container := actual.(occam.Container)
message := fmt.Sprintf("Expected\n\tdocker container id: %s\nnot to be available.", container.ID)

if logs, _ := m.Docker.Container.Logs.Execute(container.ID); logs != nil {
message = fmt.Sprintf("%s\n\nContainer logs:\n\n%s", message, logs)
}

return message
}
154 changes: 154 additions & 0 deletions matchers/be_available_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package matchers_test

import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"

"github.com/onsi/gomega/types"
"github.com/paketo-buildpacks/occam"
"github.com/paketo-buildpacks/occam/matchers"
"github.com/paketo-buildpacks/occam/matchers/fakes"
"github.com/paketo-buildpacks/packit/pexec"
"github.com/sclevine/spec"

. "github.com/onsi/gomega"
)

//go:generate faux --package github.com/paketo-buildpacks/occam --interface Executable --output fakes/executable.go

func testBeAvailable(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect

matcher types.GomegaMatcher
)

it.Before(func() {
matcher = matchers.BeAvailable()
})

context("Match", func() {
var (
actual interface{}
server *httptest.Server
)

it.Before(func() {
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}))
serverURL, err := url.Parse(server.URL)
Expect(err).NotTo(HaveOccurred())

actual = occam.Container{
Ports: map[string]string{
"8080": serverURL.Port(),
},
Env: map[string]string{
"PORT": "8080",
},
}
})

it.After(func() {
server.Close()
})

context("when the http request succeeds", func() {
it("returns true", func() {
result, err := matcher.Match(actual)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(BeTrue())
})
})

context("when the http request fails", func() {
it.Before(func() {
server.Close()
})

it("returns false", func() {
result, err := matcher.Match(actual)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(BeFalse())
})
})

context("failure cases", func() {
context("when the actual is not a container", func() {
it("returns an error", func() {
_, err := matcher.Match("not a container")
Expect(err).To(MatchError("BeAvailableMatcher expects an occam.Container, received string"))
})
})
})
})

context("FailureMessage", func() {
var actual interface{}

it.Before(func() {
executable := &fakes.Executable{}
executable.ExecuteCall.Stub = func(execution pexec.Execution) error {
fmt.Fprintln(execution.Stdout, "some logs")
return nil
}

matcher = &matchers.BeAvailableMatcher{
Docker: occam.NewDocker().WithExecutable(executable),
}

actual = occam.Container{
ID: "some-container-id",
}
})

it("returns a useful error message", func() {
message := matcher.FailureMessage(actual)
Expect(message).To(ContainSubstring(strings.TrimSpace(`
Expected
docker container id: some-container-id
to be available.
Container logs:
some logs
`)))
})
})

context("NegatedFailureMessage", func() {
var actual interface{}

it.Before(func() {
executable := &fakes.Executable{}
executable.ExecuteCall.Stub = func(execution pexec.Execution) error {
fmt.Fprintln(execution.Stdout, "some logs")
return nil
}

matcher = &matchers.BeAvailableMatcher{
Docker: occam.NewDocker().WithExecutable(executable),
}

actual = occam.Container{
ID: "some-container-id",
}
})

it("returns a useful error message", func() {
message := matcher.NegatedFailureMessage(actual)
Expect(message).To(ContainSubstring(strings.TrimSpace(`
Expected
docker container id: some-container-id
not to be available.
Container logs:
some logs
`)))
})
})
}
32 changes: 32 additions & 0 deletions matchers/fakes/executable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fakes

import (
"sync"

"github.com/paketo-buildpacks/packit/pexec"
)

type Executable struct {
ExecuteCall struct {
sync.Mutex
CallCount int
Receives struct {
Execution pexec.Execution
}
Returns struct {
Error error
}
Stub func(pexec.Execution) error
}
}

func (f *Executable) Execute(param1 pexec.Execution) error {
f.ExecuteCall.Lock()
defer f.ExecuteCall.Unlock()
f.ExecuteCall.CallCount++
f.ExecuteCall.Receives.Execution = param1
if f.ExecuteCall.Stub != nil {
return f.ExecuteCall.Stub(param1)
}
return f.ExecuteCall.Returns.Error
}
1 change: 1 addition & 0 deletions matchers/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

func TestUnitMatchers(t *testing.T) {
suite := spec.New("occam/matchers", spec.Report(report.Terminal{}))
suite("BeAvailable", testBeAvailable)
suite("ContainLines", testContainLines)
suite.Run(t)
}

0 comments on commit 49f9b28

Please sign in to comment.