aboutsummaryrefslogtreecommitdiff
path: root/ref/store/memory/batch_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'ref/store/memory/batch_test.go')
-rw-r--r--ref/store/memory/batch_test.go115
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)
+ }
+ })
+ }
+}