Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
remove local bus struct (#4435)
Browse files Browse the repository at this point in the history
removes the local bus from fault in favor of a single Bus that operates both within a local and global instance, and can be passed downstream independent of context.  Also includes some code separation in the fault package for readability.

---

#### Does this PR need a docs update or release note?

- [x] ⛔ No

#### Type of change

- [x] 🧹 Tech Debt/Cleanup

#### Test Plan

- [x] ⚡ Unit test
- [x] 💚 E2E
  • Loading branch information
ryanfkeepers authored Oct 10, 2023
1 parent ff6c1ea commit aa66675
Show file tree
Hide file tree
Showing 9 changed files with 632 additions and 553 deletions.
70 changes: 70 additions & 0 deletions src/pkg/fault/alert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package fault

import (
"github.com/alcionai/corso/src/cli/print"
)

var _ print.Printable = &Alert{}

// Alerts are informational-only notifications. The purpose of alerts is to
// provide a means of end-user communication about important events without
// needing to generate runtime failures or recoverable errors. When generating
// an alert, no other fault feature (failure, recoverable, skip, etc) should
// be in use. IE: Errors do not also get alerts, since the error itself is a
// form of end-user communication already.
type Alert struct {
Item Item `json:"item"`
Message string `json:"message"`
}

// String complies with the stringer interface.
func (a *Alert) String() string {
msg := "<nil>"

if a != nil {
msg = a.Message
}

if len(msg) == 0 {
msg = "<missing>"
}

return "Alert: " + msg
}

func (a Alert) MinimumPrintable() any {
return a
}

// Headers returns the human-readable names of properties of a skipped Item
// for printing out to a terminal.
func (a Alert) Headers() []string {
return []string{"Action", "Message", "Container", "Name", "ID"}
}

// Values populates the printable values matching the Headers list.
func (a Alert) Values() []string {
var cn string

acn, ok := a.Item.Additional[AddtlContainerName]
if ok {
str, ok := acn.(string)
if ok {
cn = str
}
}

return []string{"Alert", a.Message, cn, a.Item.Name, a.Item.ID}
}

func NewAlert(message, namespace, itemID, name string, addtl map[string]any) *Alert {
return &Alert{
Message: message,
Item: Item{
Namespace: namespace,
ID: itemID,
Name: name,
Additional: addtl,
},
}
}
88 changes: 88 additions & 0 deletions src/pkg/fault/alert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package fault_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/fault"
)

type AlertUnitSuite struct {
tester.Suite
}

func TestAlertUnitSuite(t *testing.T) {
suite.Run(t, &AlertUnitSuite{Suite: tester.NewUnitSuite(t)})
}

func (suite *AlertUnitSuite) TestAlert_String() {
var (
t = suite.T()
a fault.Alert
)

assert.Contains(t, a.String(), "Alert: <missing>")

a = fault.Alert{
Item: fault.Item{},
Message: "",
}
assert.Contains(t, a.String(), "Alert: <missing>")

a = fault.Alert{
Item: fault.Item{
ID: "item_id",
},
Message: "msg",
}
assert.NotContains(t, a.String(), "item_id")
assert.Contains(t, a.String(), "Alert: msg")
}

func (suite *AlertUnitSuite) TestNewAlert() {
t := suite.T()
addtl := map[string]any{"foo": "bar"}
a := fault.NewAlert("message-to-show", "ns", "item_id", "item_name", addtl)

expect := fault.Alert{
Item: fault.Item{
Namespace: "ns",
ID: "item_id",
Name: "item_name",
Additional: addtl,
},
Message: "message-to-show",
}

assert.Equal(t, expect, *a)
}

func (suite *AlertUnitSuite) TestAlert_HeadersValues() {
addtl := map[string]any{
fault.AddtlContainerID: "cid",
fault.AddtlContainerName: "cname",
}

table := []struct {
name string
alert *fault.Alert
expect []string
}{
{
name: "new alert",
alert: fault.NewAlert("message-to-show", "ns", "id", "name", addtl),
expect: []string{"Alert", "message-to-show", "cname", "name", "id"},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()

assert.Equal(t, []string{"Action", "Message", "Container", "Name", "ID"}, test.alert.Headers())
assert.Equal(t, test.expect, test.alert.Values())
})
}
}
25 changes: 25 additions & 0 deletions src/pkg/fault/example_fault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,28 @@ func ExampleBus_AddSkip() {

// Output: skipped processing file: malware_detected
}

// ExampleBus_AddAlert showcases when to use AddAlert.
func ExampleBus_AddAlert() {
errs := fault.New(false)

// Some events should be communicated to the end user without recording an
// error to the operation. Logs aren't sufficient because we don't promote
// log messages to the terminal. But errors and skips are too heavy and hacky
// to use. In these cases, we can create informational Alerts.
//
// Only the message gets shown to the user. But since we're persisting this
// data along with the backup details and other fault info, we have the option
// of packing any other contextual data that we want.
errs.AddAlert(ctx, fault.NewAlert(
"something important happened!",
"deduplication-namespace",
"file-id",
"file-name",
map[string]any{"foo": "bar"}))

// later on, after processing, end users can scrutinize the alerts.
fmt.Println(errs.Alerts()[0].String())

// Alert: something important happened!
}
Loading

0 comments on commit aa66675

Please sign in to comment.