mirror of
https://github.com/kopia/kopia.git
synced 2026-05-10 07:44:01 -04:00
feat(notifications): improved notification templates (#4321)
This commit is contained in:
30
notification/notifydata/error_info_test.go
Normal file
30
notification/notifydata/error_info_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package notifydata
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/kopia/kopia/internal/clock"
|
||||
)
|
||||
|
||||
func TestNewErrorInfo(t *testing.T) {
|
||||
startTime := clock.Now()
|
||||
endTime := startTime.Add(2 * time.Second)
|
||||
|
||||
err := errors.New("test error") //nolint:err113
|
||||
e := NewErrorInfo("test operation", "test details", startTime, endTime, err)
|
||||
|
||||
require.Equal(t, "test operation", e.Operation)
|
||||
require.Equal(t, "test details", e.OperationDetails)
|
||||
require.Equal(t, startTime, e.StartTime)
|
||||
require.Equal(t, endTime, e.EndTime)
|
||||
require.Equal(t, "test error", e.ErrorMessage)
|
||||
require.Equal(t, "test error", e.ErrorDetails)
|
||||
|
||||
require.Equal(t, startTime.Truncate(time.Second), e.StartTimestamp())
|
||||
require.Equal(t, endTime.Truncate(time.Second), e.EndTimestamp())
|
||||
require.Equal(t, 2*time.Second, e.Duration())
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package notifydata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kopia/kopia/snapshot"
|
||||
@@ -56,19 +58,6 @@ func (m *ManifestWithError) TotalSizeDelta() int64 {
|
||||
return m.Manifest.RootEntry.FileSize
|
||||
}
|
||||
|
||||
// New returns the total size of the snapshot in bytes.
|
||||
func (m *ManifestWithError) New() int64 {
|
||||
if m.Manifest.RootEntry == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
if m.Manifest.RootEntry.DirSummary != nil {
|
||||
return m.Manifest.RootEntry.DirSummary.TotalFileSize
|
||||
}
|
||||
|
||||
return m.Manifest.RootEntry.FileSize
|
||||
}
|
||||
|
||||
// TotalFiles returns the total number of files in the snapshot.
|
||||
func (m *ManifestWithError) TotalFiles() int64 {
|
||||
if m.Manifest.RootEntry == nil {
|
||||
@@ -134,30 +123,81 @@ func (m *ManifestWithError) Duration() time.Duration {
|
||||
return time.Duration(m.Manifest.EndTime - m.Manifest.StartTime).Round(durationPrecision)
|
||||
}
|
||||
|
||||
// Status codes.
|
||||
const (
|
||||
StatusCodeIncomplete = "incomplete"
|
||||
StatusCodeFatal = "fatal"
|
||||
StatusCodeError = "error"
|
||||
StatusCodeSuccess = "success"
|
||||
)
|
||||
|
||||
// StatusCode returns the status code of the manifest.
|
||||
func (m *ManifestWithError) StatusCode() string {
|
||||
if m.Error != "" {
|
||||
return "fatal"
|
||||
return StatusCodeFatal
|
||||
}
|
||||
|
||||
if m.Manifest.IncompleteReason != "" {
|
||||
return "incomplete"
|
||||
return StatusCodeIncomplete
|
||||
}
|
||||
|
||||
if m.Manifest.RootEntry != nil && m.Manifest.RootEntry.DirSummary != nil {
|
||||
if m.Manifest.RootEntry.DirSummary.FatalErrorCount > 0 {
|
||||
return "fatal"
|
||||
return StatusCodeFatal
|
||||
}
|
||||
|
||||
if m.Manifest.RootEntry.DirSummary.IgnoredErrorCount > 0 {
|
||||
return "error"
|
||||
return StatusCodeError
|
||||
}
|
||||
}
|
||||
|
||||
return "ok"
|
||||
return StatusCodeSuccess
|
||||
}
|
||||
|
||||
// MultiSnapshotStatus represents the status of multiple snapshots.
|
||||
type MultiSnapshotStatus struct {
|
||||
Snapshots []*ManifestWithError `json:"snapshots"`
|
||||
}
|
||||
|
||||
// OverallStatus returns the overall status of the snapshots.
|
||||
func (m MultiSnapshotStatus) OverallStatus() string {
|
||||
var (
|
||||
numIncomplete int
|
||||
numFatal int
|
||||
numErrors int
|
||||
numSuccess int
|
||||
)
|
||||
|
||||
for _, s := range m.Snapshots {
|
||||
switch s.StatusCode() {
|
||||
case StatusCodeIncomplete:
|
||||
numIncomplete++
|
||||
case StatusCodeError:
|
||||
numErrors++
|
||||
case StatusCodeFatal:
|
||||
numFatal++
|
||||
case StatusCodeSuccess:
|
||||
numSuccess++
|
||||
}
|
||||
}
|
||||
|
||||
var errorStrings []string
|
||||
|
||||
if numFatal > 1 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("%d fatal errors", numFatal))
|
||||
} else if numFatal == 1 {
|
||||
errorStrings = append(errorStrings, "a fatal error")
|
||||
}
|
||||
|
||||
if numErrors > 1 {
|
||||
errorStrings = append(errorStrings, fmt.Sprintf("%d errors", numErrors))
|
||||
} else if numErrors == 1 {
|
||||
errorStrings = append(errorStrings, "an error")
|
||||
}
|
||||
|
||||
if len(errorStrings) == 0 {
|
||||
return "success"
|
||||
}
|
||||
|
||||
return "encountered " + strings.Join(errorStrings, " and ")
|
||||
}
|
||||
|
||||
611
notification/notifydata/multi_snapshot_status_test.go
Normal file
611
notification/notifydata/multi_snapshot_status_test.go
Normal file
@@ -0,0 +1,611 @@
|
||||
package notifydata_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
"github.com/kopia/kopia/internal/clock"
|
||||
"github.com/kopia/kopia/notification/notifydata"
|
||||
"github.com/kopia/kopia/snapshot"
|
||||
)
|
||||
|
||||
func TestOverallStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
snapshots []*notifydata.ManifestWithError
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "all success",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
},
|
||||
expected: "success",
|
||||
},
|
||||
{
|
||||
name: "one fatal error",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{}, Error: "fatal error"},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
},
|
||||
expected: "encountered a fatal error",
|
||||
},
|
||||
{
|
||||
name: "multiple fatal errors",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{}, Error: "fatal error"},
|
||||
{Manifest: snapshot.Manifest{}, Error: "fatal error"},
|
||||
},
|
||||
expected: "encountered 2 fatal errors",
|
||||
},
|
||||
{
|
||||
name: "one error",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
},
|
||||
expected: "encountered an error",
|
||||
},
|
||||
{
|
||||
name: "one fatal error and two errors",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{}, Error: "fatal error"},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
},
|
||||
expected: "encountered a fatal error and 2 errors",
|
||||
},
|
||||
{
|
||||
name: "one fatal error and one errors",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{}, Error: "fatal error"},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
},
|
||||
expected: "encountered a fatal error and an error",
|
||||
},
|
||||
{
|
||||
name: "multiple errors",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
{Manifest: snapshot.Manifest{RootEntry: &snapshot.DirEntry{DirSummary: &fs.DirectorySummary{IgnoredErrorCount: 1}}}},
|
||||
},
|
||||
expected: "encountered 2 errors",
|
||||
},
|
||||
{
|
||||
name: "incomplete snapshot",
|
||||
snapshots: []*notifydata.ManifestWithError{
|
||||
{Manifest: snapshot.Manifest{IncompleteReason: "incomplete"}},
|
||||
{Manifest: snapshot.Manifest{}},
|
||||
},
|
||||
expected: "success",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mss := notifydata.MultiSnapshotStatus{Snapshots: tt.snapshots}
|
||||
require.Equal(t, tt.expected, mss.OverallStatus())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusCode(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "fatal error",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Error: "fatal error",
|
||||
},
|
||||
expected: notifydata.StatusCodeFatal,
|
||||
},
|
||||
{
|
||||
name: "incomplete snapshot",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
IncompleteReason: "incomplete",
|
||||
},
|
||||
},
|
||||
expected: notifydata.StatusCodeIncomplete,
|
||||
},
|
||||
{
|
||||
name: "fatal error in dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
FatalErrorCount: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: notifydata.StatusCodeFatal,
|
||||
},
|
||||
{
|
||||
name: "ignored error in dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
IgnoredErrorCount: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: notifydata.StatusCodeError,
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{},
|
||||
},
|
||||
expected: notifydata.StatusCodeSuccess,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.StatusCode())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestManifestWithErrorMethods(t *testing.T) {
|
||||
startTime := clock.Now().Add(-1*time.Minute - 330*time.Millisecond)
|
||||
endTime := clock.Now()
|
||||
|
||||
dirSummary := &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
TotalFileCount: 10,
|
||||
TotalDirCount: 5,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected struct {
|
||||
startTimestamp time.Time
|
||||
endTimestamp time.Time
|
||||
totalSize int64
|
||||
totalFiles int64
|
||||
totalDirs int64
|
||||
duration time.Duration
|
||||
}
|
||||
}{
|
||||
{
|
||||
name: "complete manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
StartTime: fs.UTCTimestamp(startTime.UnixNano()),
|
||||
EndTime: fs.UTCTimestamp(endTime.UnixNano()),
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: dirSummary,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: struct {
|
||||
startTimestamp time.Time
|
||||
endTimestamp time.Time
|
||||
totalSize int64
|
||||
totalFiles int64
|
||||
totalDirs int64
|
||||
duration time.Duration
|
||||
}{
|
||||
startTimestamp: startTime.UTC().Truncate(time.Second),
|
||||
endTimestamp: endTime.UTC().Truncate(time.Second),
|
||||
totalSize: 1000,
|
||||
totalFiles: 10,
|
||||
totalDirs: 5,
|
||||
duration: endTime.Sub(startTime).Truncate(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{},
|
||||
},
|
||||
expected: struct {
|
||||
startTimestamp time.Time
|
||||
endTimestamp time.Time
|
||||
totalSize int64
|
||||
totalFiles int64
|
||||
totalDirs int64
|
||||
duration time.Duration
|
||||
}{
|
||||
startTimestamp: time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
endTimestamp: time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
totalSize: 0,
|
||||
totalFiles: 0,
|
||||
totalDirs: 0,
|
||||
duration: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected.startTimestamp, tt.manifest.StartTimestamp())
|
||||
require.Equal(t, tt.expected.endTimestamp, tt.manifest.EndTimestamp())
|
||||
require.Equal(t, tt.expected.totalSize, tt.manifest.TotalSize())
|
||||
require.Equal(t, tt.expected.totalFiles, tt.manifest.TotalFiles())
|
||||
require.Equal(t, tt.expected.totalDirs, tt.manifest.TotalDirs())
|
||||
require.Equal(t, tt.expected.duration, tt.manifest.Duration())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalSizeDelta(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no previous manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no root entry in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no dir summary in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
FileSize: 500,
|
||||
},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 500,
|
||||
},
|
||||
{
|
||||
name: "dir summary in both manifests",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1500,
|
||||
},
|
||||
},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 500,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalSizeDelta())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalFilesDelta(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no previous manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no root entry in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no dir summary in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "dir summary in both manifests",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalFilesDelta())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalDirsDelta(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no previous manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no root entry in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no dir summary in current manifest",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "dir summary in both manifests",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
Previous: &snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalDirsDelta())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalFiles(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no root entry",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "root entry with dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileCount: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 10,
|
||||
},
|
||||
{
|
||||
name: "root entry without dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{},
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalFiles())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalDirs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no root entry",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "root entry with dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalDirCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
name: "root entry without dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalDirs())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
manifest notifydata.ManifestWithError
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "no root entry",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "root entry with dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
DirSummary: &fs.DirectorySummary{
|
||||
TotalFileSize: 1000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 1000,
|
||||
},
|
||||
{
|
||||
name: "root entry without dir summary",
|
||||
manifest: notifydata.ManifestWithError{
|
||||
Manifest: snapshot.Manifest{
|
||||
RootEntry: &snapshot.DirEntry{
|
||||
FileSize: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 500,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.Equal(t, tt.expected, tt.manifest.TotalSize())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
@@ -187,7 +188,9 @@ func verifyTemplate(t *testing.T, embeddedTemplateName, expectedSuffix string, a
|
||||
|
||||
want := string(wantBytes)
|
||||
|
||||
require.Equal(t, want, buf.String())
|
||||
assert.Equal(t, want, buf.String())
|
||||
|
||||
require.NoError(t, os.Remove(actualFileName))
|
||||
if want == buf.String() {
|
||||
require.NoError(t, os.Remove(actualFileName))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Subject: Kopia created {{ len .EventArgs.Snapshots }} snapshot{{ if gt (len .EventArgs.Snapshots) 1 }}s{{end}} on {{.Hostname}}
|
||||
Subject: Kopia {{.EventArgs.OverallStatus}} creating {{ if gt (len .EventArgs.Snapshots) 1 }}{{ len .EventArgs.Snapshots }} snapshots{{else}}snapshot{{end}} on {{.Hostname}}
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Subject: Kopia created {{ len .EventArgs.Snapshots }} snapshot{{ if gt (len .EventArgs.Snapshots) 1 }}s{{end}} on {{.Hostname}}
|
||||
|
||||
Subject: Kopia {{.EventArgs.OverallStatus}} creating {{ if gt (len .EventArgs.Snapshots) 1 }}{{ len .EventArgs.Snapshots }} snapshots{{else}}snapshot{{end}} on {{.Hostname}}
|
||||
{{ range .EventArgs.Snapshots | sortSnapshotManifestsByName}}Path: {{ .Manifest.Source.Path }}
|
||||
|
||||
Status: {{ .StatusCode }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Subject: Kopia created 4 snapshots on some-host
|
||||
Subject: Kopia encountered a fatal error creating 4 snapshots on some-host
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
@@ -90,7 +90,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path</span></td>
|
||||
<td>Wed, 01 Jan 2020 19:04:05 PST</td>
|
||||
<td>1.1s</td>
|
||||
@@ -104,7 +104,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
@@ -121,7 +121,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path</span></td>
|
||||
<td>Wed, 01 Jan 2020 19:04:05 PST</td>
|
||||
<td>1.1s</td>
|
||||
@@ -135,7 +135,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
@@ -152,7 +152,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path2</span></td>
|
||||
<td>Wed, 01 Jan 2020 19:04:05 PST</td>
|
||||
<td>1.1s</td>
|
||||
@@ -166,7 +166,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Subject: Kopia created 4 snapshots on some-host
|
||||
Subject: Kopia encountered a fatal error creating 4 snapshots on some-host
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
@@ -90,7 +90,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path</span></td>
|
||||
<td>Thu, 02 Jan 2020 03:04:05 +0000</td>
|
||||
<td>1.1s</td>
|
||||
@@ -104,7 +104,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
@@ -121,7 +121,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path</span></td>
|
||||
<td>Thu, 02 Jan 2020 03:04:05 +0000</td>
|
||||
<td>1.1s</td>
|
||||
@@ -135,7 +135,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
@@ -152,7 +152,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td><span class="path">/some/path2</span></td>
|
||||
<td>Thu, 02 Jan 2020 03:04:05 +0000</td>
|
||||
<td>1.1s</td>
|
||||
@@ -166,7 +166,7 @@ Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
|
||||
|
||||
<tr class="snapshotstatus-ok">
|
||||
<tr class="snapshotstatus-success">
|
||||
<td colspan="6">
|
||||
<b style="color:red">Failed Entries:</b>
|
||||
<ul>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
Subject: Kopia encountered a fatal error creating 4 snapshots on some-host
|
||||
Path: /some/other/path
|
||||
|
||||
Status: fatal
|
||||
@@ -12,7 +11,7 @@ Path: /some/other/path
|
||||
|
||||
Path: /some/path
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Wed, 01 Jan 2020 19:04:05 PST
|
||||
Duration: 1.1s
|
||||
Size: 456 B (+56 B)
|
||||
@@ -26,7 +25,7 @@ Path: /some/path
|
||||
|
||||
Path: /some/path
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Wed, 01 Jan 2020 19:04:05 PST
|
||||
Duration: 1.1s
|
||||
Size: 456 B (-44 B)
|
||||
@@ -40,7 +39,7 @@ Path: /some/path
|
||||
|
||||
Path: /some/path2
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Wed, 01 Jan 2020 19:04:05 PST
|
||||
Duration: 1.1s
|
||||
Size: 456 B
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Subject: Kopia created 4 snapshots on some-host
|
||||
|
||||
Subject: Kopia encountered a fatal error creating 4 snapshots on some-host
|
||||
Path: /some/other/path
|
||||
|
||||
Status: fatal
|
||||
@@ -12,7 +11,7 @@ Path: /some/other/path
|
||||
|
||||
Path: /some/path
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Thu, 02 Jan 2020 03:04:05 +0000
|
||||
Duration: 1.1s
|
||||
Size: 456 B (+56 B)
|
||||
@@ -26,7 +25,7 @@ Path: /some/path
|
||||
|
||||
Path: /some/path
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Thu, 02 Jan 2020 03:04:05 +0000
|
||||
Duration: 1.1s
|
||||
Size: 456 B (-44 B)
|
||||
@@ -40,7 +39,7 @@ Path: /some/path
|
||||
|
||||
Path: /some/path2
|
||||
|
||||
Status: ok
|
||||
Status: success
|
||||
Start: Thu, 02 Jan 2020 03:04:05 +0000
|
||||
Duration: 1.1s
|
||||
Size: 456 B
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// Message represents a notification message.
|
||||
type Message struct {
|
||||
Subject string `json:"subject"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
Severity Severity `json:"severity"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user