From f6e69200944a1fbc0f1fc0ecd8beb2f8659161c1 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 29 May 2026 16:46:50 +0300 Subject: refactor(sync): move backup session state to Syncer instance (qq) --- internal/sync/backup_test.go | 63 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'internal/sync/backup_test.go') diff --git a/internal/sync/backup_test.go b/internal/sync/backup_test.go index 9bdbff3..fd15d04 100644 --- a/internal/sync/backup_test.go +++ b/internal/sync/backup_test.go @@ -2,15 +2,15 @@ package sync import ( "errors" + "fmt" + stdsync "sync" + "sync/atomic" "testing" "codeberg.org/snonux/gitsyncer/internal/config" ) func TestHandlePushError_DisablesBackupForSession(t *testing.T) { - resetBackupSessionState() - t.Cleanup(resetBackupSessionState) - syncer := &Syncer{} syncer.SetBackupEnabled(true) @@ -24,9 +24,6 @@ func TestHandlePushError_DisablesBackupForSession(t *testing.T) { } func TestHandlePushError_PropagatesPrimaryRemoteFailure(t *testing.T) { - resetBackupSessionState() - t.Cleanup(resetBackupSessionState) - syncer := &Syncer{} syncer.SetBackupEnabled(true) @@ -37,6 +34,60 @@ func TestHandlePushError_PropagatesPrimaryRemoteFailure(t *testing.T) { } } +func TestHandlePushError_BackupDisableIsIsolatedPerSyncer(t *testing.T) { + backupOrg := &config.Organization{BackupLocation: true} + + syncerA := &Syncer{} + syncerA.SetBackupEnabled(true) + + syncerB := &Syncer{} + syncerB.SetBackupEnabled(true) + + err := syncerA.handlePushError("backup-a", backupOrg, errors.New("dial tcp: connection refused")) + if err != nil { + t.Fatalf("expected backup push failure to be downgraded, got %v", err) + } + + if syncerA.backupActive() { + t.Fatal("expected syncerA backup sync to be disabled for the remainder of the session") + } + if !syncerB.backupActive() { + t.Fatal("expected syncerB backup session to remain active") + } +} + +func TestBackupSessionState_DisableIsThreadSafe(t *testing.T) { + var session backupSessionState + var firstDisableCount atomic.Int32 + + const workers = 32 + var wg stdsync.WaitGroup + wg.Add(workers) + + for i := 0; i < workers; i++ { + go func(i int) { + defer wg.Done() + if session.disable(fmt.Sprintf("reason-%d", i)) { + firstDisableCount.Add(1) + } + }(i) + } + + wg.Wait() + + if got := firstDisableCount.Load(); got != 1 { + t.Fatalf("expected exactly one successful disable transition, got %d", got) + } + + disabled, reason := session.status() + if !disabled { + t.Fatal("expected backup session to be disabled") + } + if reason == "" { + t.Fatal("expected disable reason to be recorded") + } +} + func TestParseSSHLocation_SupportsSSHURLWithPort(t *testing.T) { t.Parallel() -- cgit v1.2.3