mirror of
https://github.com/kopia/kopia.git
synced 2026-01-30 17:23:18 -05:00
* feat(cli): send error notifications and snapshot reports Notifications will be sent to all configured notification profiles according to their severity levels. The following events will trigger notifications: - Snapshot is created (CLI only, severity >= report) - Server Maintenance error occurs (CLI, server and UI, severity >= error) - Any other CLI error occurs (CLI only, severity >= error). A flag `--no-error-notifications` can be used to disable error notifications. * added template tests * improved time formatting in templates * plumb through notifytemplate.Options * more testing for formatting options * fixed default date format to RFC1123
105 lines
2.4 KiB
Go
105 lines
2.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/kopia/kopia/internal/clock"
|
|
"github.com/kopia/kopia/internal/repotesting"
|
|
"github.com/kopia/kopia/notification/notifytemplate"
|
|
"github.com/kopia/kopia/repo"
|
|
"github.com/kopia/kopia/repo/maintenance"
|
|
)
|
|
|
|
type testServer struct {
|
|
mu sync.Mutex
|
|
|
|
runCounter atomic.Int32
|
|
refreshSchedulerCount atomic.Int32
|
|
|
|
log func(msg string, args ...any)
|
|
|
|
// +checklocks:mu
|
|
err error
|
|
}
|
|
|
|
func (s *testServer) runMaintenanceTask(ctx context.Context, dr repo.DirectRepository) error {
|
|
s.runCounter.Add(1)
|
|
|
|
if s.log != nil {
|
|
s.log("runMaintenanceTask")
|
|
}
|
|
|
|
s.mu.Lock()
|
|
ne := s.err
|
|
s.err = nil
|
|
s.mu.Unlock()
|
|
|
|
return ne
|
|
}
|
|
|
|
func (s *testServer) refreshScheduler(reason string) {
|
|
s.refreshSchedulerCount.Add(1)
|
|
}
|
|
|
|
func (s *testServer) enableErrorNotifications() bool {
|
|
return false
|
|
}
|
|
|
|
func (s *testServer) notificationTemplateOptions() notifytemplate.Options {
|
|
return notifytemplate.DefaultOptions
|
|
}
|
|
|
|
func TestServerMaintenance(t *testing.T) {
|
|
ctx, env := repotesting.NewEnvironment(t, repotesting.FormatNotImportant)
|
|
|
|
require.NoError(t, repo.DirectWriteSession(ctx, env.RepositoryWriter, repo.WriteSessionOptions{}, func(ctx context.Context, dw repo.DirectRepositoryWriter) error {
|
|
return maintenance.SetParams(ctx, dw, &maintenance.Params{
|
|
Owner: env.Repository.ClientOptions().UsernameAtHost(),
|
|
QuickCycle: maintenance.CycleParams{
|
|
Enabled: true,
|
|
Interval: 5 * time.Second,
|
|
},
|
|
FullCycle: maintenance.CycleParams{
|
|
Enabled: true,
|
|
Interval: 10 * time.Second,
|
|
},
|
|
})
|
|
}))
|
|
|
|
ts := &testServer{log: t.Logf}
|
|
|
|
mm := startMaintenanceManager(ctx, env.RepositoryWriter, ts, time.Minute)
|
|
require.Equal(t, time.Time{}, mm.nextMaintenanceNoEarlierThan)
|
|
|
|
defer mm.stop(ctx)
|
|
|
|
// trigger and make sure it runs
|
|
mm.trigger()
|
|
require.Eventually(t, func() bool {
|
|
return ts.runCounter.Load() == 1 && ts.refreshSchedulerCount.Load() == 1
|
|
}, 3*time.Second, 10*time.Millisecond)
|
|
|
|
ts.mu.Lock()
|
|
ts.err = errors.New("some error")
|
|
ts.mu.Unlock()
|
|
|
|
mm.trigger()
|
|
|
|
require.Eventually(t, func() bool {
|
|
mm.mu.Lock()
|
|
defer mm.mu.Unlock()
|
|
|
|
return ts.runCounter.Load() == 2 && !mm.nextMaintenanceNoEarlierThan.IsZero()
|
|
}, 3*time.Second, 10*time.Millisecond)
|
|
|
|
// after a failure next maintenance time should be deferred by a minute.
|
|
require.Greater(t, mm.nextMaintenanceTime().Sub(clock.Now()), 50*time.Second)
|
|
}
|