package release import ( "bytes" "context" "errors" "os" "testing" ) type heldSystemPublicationStore struct { Store key string entered chan struct{} resume chan struct{} } func (s heldSystemPublicationStore) Put(ctx context.Context, key string, raw []byte, etag string) (string, error) { if key == s.key { close(s.entered) <-s.resume } return s.Store.Put(ctx, key, raw, etag) } func TestSystemPublicationCancellationWinsDelayedCAS(t *testing.T) { for _, existing := range []bool{false, true} { name := "absent" if existing { name = "existing" } t.Run(name, func(t *testing.T) { ctx := t.Context() key, pub := testKeys(t) sg := RootSigner(key) store := NewDirStore(t.TempDir()) if existing { if _, err := PromoteSystem(ctx, store, sg, "router", "stable", testSystemRelease("v1.0.0"), SystemPromoteOptions{}); err != nil { t.Fatal(err) } } prepared, err := PrepareSystemPromotion(ctx, store, sg, "router", "stable", testSystemRelease("v1.1.0"), SystemPromoteOptions{}, "cancelled-update") if err != nil { t.Fatal(err) } held := heldSystemPublicationStore{Store: store, key: SystemPointerKey("router", "stable"), entered: make(chan struct{}), resume: make(chan struct{})} done := make(chan error, 1) go func() { _, err := PublishSystemPublication(ctx, held, pub, prepared); done <- err }() <-held.entered if err := CancelSystemPublication(ctx, store, sg, prepared); err != nil { close(held.resume) t.Fatal(err) } close(held.resume) if err := <-done; !errors.Is(err, ErrCASConflict) { t.Fatalf("delayed CAS: %v", err) } if err := CancelSystemPublication(ctx, store, sg, prepared); err != nil { t.Fatalf("cancel retry: %v", err) } p, etag, err := GetSystemPointer(ctx, store, pub, "router", "stable") if existing { if err != nil || p.Current.Version != "v1.0.0" { t.Fatal(p, err) } } else if !errors.Is(err, os.ErrNotExist) || etag == "" { t.Fatalf("tombstone read: %s %v", etag, err) } if _, err := PromoteSystem(ctx, store, sg, "router", "stable", testSystemRelease("v1.2.0"), SystemPromoteOptions{}); err != nil { t.Fatalf("new promotion after fence: %v", err) } if _, err := PublishSystemPublication(ctx, store, pub, prepared); !errors.Is(err, ErrCASConflict) { t.Fatalf("cancelled activation resurrected: %v", err) } }) } } func TestSystemPublicationCancellationCannotUndoCommittedUpdate(t *testing.T) { ctx := t.Context() key, pub := testKeys(t) sg := RootSigner(key) store := NewDirStore(t.TempDir()) p, err := PrepareSystemPromotion(ctx, store, sg, "router", "stable", testSystemRelease("v1.0.0"), SystemPromoteOptions{}, "committed-update") if err != nil { t.Fatal(err) } if _, err := PublishSystemPublication(ctx, store, pub, p); err != nil { t.Fatal(err) } if err := CancelSystemPublication(ctx, store, sg, p); !errors.Is(err, ErrCASConflict) { t.Fatal(err) } raw, _, err := store.Get(ctx, SystemPointerKey("router", "stable")) if err != nil || !bytes.Equal(raw, p.After) { t.Fatal("committed publication changed", err) } }