diff options
Diffstat (limited to 'ref/store/memory/batch_test.go')
| -rw-r--r-- | ref/store/memory/batch_test.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/ref/store/memory/batch_test.go b/ref/store/memory/batch_test.go new file mode 100644 index 00000000..518dc7b9 --- /dev/null +++ b/ref/store/memory/batch_test.go @@ -0,0 +1,115 @@ +package memory_test + +import ( + "errors" + "testing" + + "lindenii.org/go/furgit/object/id" + "lindenii.org/go/furgit/ref" + "lindenii.org/go/furgit/ref/store" + "lindenii.org/go/furgit/ref/store/memory" +) + +func TestBatchRejectsDuplicateResolvedTargetAndAppliesRemainder(t *testing.T) { + t.Parallel() + + for _, objectFormat := range id.SupportedObjectFormats() { + t.Run(objectFormat.String(), func(t *testing.T) { + t.Parallel() + + m := memory.New(objectFormat) + mainID := objectFormat.Sum([]byte("main")) + devID := objectFormat.Sum([]byte("dev")) + nextMainID := objectFormat.Sum([]byte("next-main")) + nextDevID := objectFormat.Sum([]byte("next-dev")) + aliasID := objectFormat.Sum([]byte("alias")) + + seed(t, m, func(tx store.Transaction) { + err := tx.Create("refs/heads/main", mainID) + if err != nil { + t.Fatalf("Create(main): %v", err) + } + + err = tx.Create("refs/heads/dev", devID) + if err != nil { + t.Fatalf("Create(dev): %v", err) + } + + err = tx.CreateSymbolic("refs/heads/alias", "refs/heads/main") + if err != nil { + t.Fatalf("CreateSymbolic(alias): %v", err) + } + }) + + batch, err := m.BeginBatch() + if err != nil { + t.Fatalf("BeginBatch: %v", err) + } + + err = batch.Update("refs/heads/main", nextMainID, mainID) + if err != nil { + t.Fatalf("Update(main): %v", err) + } + + // Updates the symbolic alias in deref mode, + // which resolves to refs/heads/main + // and therefore duplicates the first operation. + err = batch.Update("refs/heads/alias", aliasID, mainID) + if err != nil { + t.Fatalf("Update(alias): %v", err) + } + + err = batch.Update("refs/heads/dev", nextDevID, devID) + if err != nil { + t.Fatalf("Update(dev): %v", err) + } + + results, err := batch.Apply() + if err != nil { + t.Fatalf("Apply: %v", err) + } + + if len(results) != 3 { + t.Fatalf("len(results) = %d, want 3", len(results)) + } + + if results[0].Status != store.BatchStatusApplied { + t.Fatalf("results[0].Status = %v, want applied", results[0].Status) + } + + if results[1].Status != store.BatchStatusRejected { + t.Fatalf("results[1].Status = %v, want rejected", results[1].Status) + } + + if !errors.Is(results[1].Error, store.ErrDuplicateUpdate) { + t.Fatalf("results[1].Error = %v, want ErrDuplicateUpdate", results[1].Error) + } + + if results[2].Status != store.BatchStatusApplied { + t.Fatalf("results[2].Status = %v, want applied", results[2].Status) + } + + if got := resolveDirect(t, m, "refs/heads/main").ID; got != nextMainID { + t.Fatalf("main after batch = %v, want %v", got, nextMainID) + } + + if got := resolveDirect(t, m, "refs/heads/dev").ID; got != nextDevID { + t.Fatalf("dev after batch = %v, want %v", got, nextDevID) + } + + resolved, err := m.Resolve("refs/heads/alias") + if err != nil { + t.Fatalf("Resolve(alias): %v", err) + } + + symbolic, ok := resolved.(ref.Symbolic) + if !ok { + t.Fatalf("Resolve(alias) = %T, want ref.Symbolic", resolved) + } + + if symbolic.Target != "refs/heads/main" { + t.Fatalf("alias target = %q, want refs/heads/main", symbolic.Target) + } + }) + } +} |
