Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ping and tests #16

Merged
merged 11 commits into from
Sep 29, 2022
15 changes: 14 additions & 1 deletion pkg/ctl/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,20 @@ func (c *ctl) Ping(opts *SelectorConfig) (map[string]heartbeat.PingResult, error
return nil, ErrNoSelector
}

return make(map[string]heartbeat.PingResult), nil
heartbeats, err := c.Get(opts)
if err != nil {
return nil, err
}

var pingResults = make(map[string]heartbeat.PingResult)
for _, h := range heartbeats {
result, err := c.repo.Ping(context.Background(), h.Name)
if err != nil {
return pingResults, fmt.Errorf("heartbeat \"%s\" failed: %w", h.Name, err)
}
pingResults[h.Name] = *result
}
return pingResults, nil
}

// enableDisableHeartbeats applies given method (can be either `repo.Enable` or
Expand Down
103 changes: 91 additions & 12 deletions pkg/ctl/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
GetMethodName = "Get"
EnableMethodName = "Enable"
DisableMethodName = "Disable"
PingMethodName = "Ping"
)

func getName(h heartbeat.Heartbeat) string {
Expand Down Expand Up @@ -68,6 +69,24 @@ var _ = Describe("Adapter", func() {
adapter = ctl.NewCtl(repo)
})

When("no heartbeats are configured", func() {
BeforeEach(func() {
configuredHeartbeats = []heartbeat.Heartbeat{}
})

Context(GetMethodName, func() {
It("returns an empty list and no error", func() {
Expect(adapter.Get(&ctl.SelectorConfig{})).To(BeEmpty())
})

It("ignores selector options", func() {
Expect(adapter.Get(&ctl.SelectorConfig{
LabelSelector: "name=foo",
})).To(BeEmpty())
})
})
})

When("heartbeats are configured", func() {
BeforeEach(func() {
configuredHeartbeats = []heartbeat.Heartbeat{
Expand Down Expand Up @@ -268,25 +287,72 @@ var _ = Describe("Adapter", func() {

AssertMethodFailsFastWhenRepoCallFails(EnableMethodName)
AssertMethodFailsFastWhenRepoCallFails(DisableMethodName)
})

When("no heartbeats are configured", func() {
BeforeEach(func() {
configuredHeartbeats = []heartbeat.Heartbeat{}
})
Context(PingMethodName, func() {
var (
expected []string
expectedInfos map[string]heartbeat.PingResult = make(map[string]heartbeat.PingResult)
)

Context(GetMethodName, func() {
It("returns an empty list and no error", func() {
Expect(adapter.Get(&ctl.SelectorConfig{})).To(BeEmpty())
JustBeforeEach(func() {
expected = []string{"foo-oof1", "bar-oof2"}
for _, hbName := range expected {
ping := &heartbeat.PingResult{
Message: "PONG - Heartbeat received",
}

repo.EXPECT().Ping(gomock.Any(), hbName).Return(ping, nil)
expectedInfos[hbName] = *ping
}
})

It("ignores selector options", func() {
Expect(adapter.Get(&ctl.SelectorConfig{
LabelSelector: "name=foo",
})).To(BeEmpty())
It("calls Ping on heartbeats selected by given options", func() {
Expect(adapter.Ping(&ctl.SelectorConfig{
NameExpressions: []string{"foo.*", ".*-oof[12]"},
LabelSelector: "enabled",
FieldSelector: "alertPriority=P3",
})).To(Equal(expectedInfos))
})
})

Context(PingMethodName, func() {
It("fails fast when first repo call on a heartbeat fails", func() {
By("making first heartbeat succeed and second fail")

fooPingResult := &heartbeat.PingResult{
Message: "PONG - Heartbeat received",
}
apiErr := errors.New("API call failed")

repo.EXPECT().Ping(gomock.Any(), "foo").Return(fooPingResult, nil)
repo.EXPECT().Ping(gomock.Any(), "foo-oof1").Return(nil, apiErr)

By("calling adapter method")

pingResults, err := adapter.Ping(&ctl.SelectorConfig{
NameExpressions: []string{"foo.*"},
})

By("ensuring we get an error")

Expect(err).To(SatisfyAll(
MatchError(apiErr),
// assert that error tells us which heartbeat caused the error
WithTransform(
func(e error) string { return e.Error() },
ContainSubstring("foo-oof1"),
),
))

By("ensuring we also get info about the heartbeat that succeeded")

Expect(pingResults).To(Equal(map[string]heartbeat.PingResult{
"foo": *fooPingResult,
}))
})
})
})

})

Describe("failure modes", func() {
Expand Down Expand Up @@ -315,6 +381,8 @@ var _ = Describe("Adapter", func() {
_, err = adapter.Enable(opts)
case DisableMethodName:
_, err = adapter.Disable(opts)
case PingMethodName:
_, err = adapter.Ping(opts)
}

Expect(err).NotTo(Succeed())
Expand All @@ -326,6 +394,7 @@ var _ = Describe("Adapter", func() {
AssertMethodPropagatesError(GetMethodName)
AssertMethodPropagatesError(EnableMethodName)
AssertMethodPropagatesError(DisableMethodName)
AssertMethodPropagatesError(PingMethodName)
})

When("no selectors are given", func() {
Expand Down Expand Up @@ -354,6 +423,16 @@ var _ = Describe("Adapter", func() {

AssertMethodFails(EnableMethodName)
AssertMethodFails(DisableMethodName)

Context(PingMethodName, func() {
It("fails", func() {
results, err := adapter.Ping(&ctl.SelectorConfig{})
Expect(err).To(MatchError(
"No selector options given, to target all heartbeats pass '.*' name expression explicitly.",
))
Expect(results).To(BeNil())
})
})
})
})
})