Implement app update orchestration (T-402)

This commit is contained in:
ila
2026-07-19 21:39:33 +08:00
parent fda52a57ca
commit 339beaa9b3
19 changed files with 1095 additions and 11 deletions
@@ -1,9 +1,11 @@
package windows
import (
"context"
"errors"
"path/filepath"
"testing"
"time"
)
func TestPlatformStubContract(t *testing.T) {
@@ -78,6 +80,71 @@ func TestVersionSupports(t *testing.T) {
}
}
func TestWaitForExit(t *testing.T) {
initial := time.Date(2026, 7, 19, 0, 0, 0, 0, time.UTC)
errSnapshot := errors.New("snapshot failed")
tests := []struct {
name string
ctx context.Context
running []bool
runErr error
timeout time.Duration
wantErr error
wantSleeps int
}{
{name: "already stopped", ctx: context.Background(), running: []bool{false}, timeout: time.Second},
{name: "stops after one poll", ctx: context.Background(), running: []bool{true, false}, timeout: time.Second, wantSleeps: 1},
{name: "timeout", ctx: context.Background(), running: []bool{true, true, true, true, true}, timeout: time.Second, wantErr: context.DeadlineExceeded, wantSleeps: 4},
{name: "snapshot failure", ctx: context.Background(), runErr: errSnapshot, timeout: time.Second, wantErr: errSnapshot},
{name: "canceled", ctx: canceledWaitContext(), running: []bool{true}, timeout: time.Second, wantErr: context.Canceled},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
clock := &fakeExitWaitClock{now: initial}
index := 0
err := waitForExit(test.ctx, test.timeout, func() (bool, error) {
if test.runErr != nil {
return false, test.runErr
}
if index >= len(test.running) {
return test.running[len(test.running)-1], nil
}
running := test.running[index]
index++
return running, nil
}, clock)
if !errors.Is(err, test.wantErr) {
t.Fatalf("waitForExit() error = %v, want %v", err, test.wantErr)
}
if clock.sleeps != test.wantSleeps {
t.Fatalf("sleeps = %d, want %d", clock.sleeps, test.wantSleeps)
}
})
}
}
func canceledWaitContext() context.Context {
ctx, cancel := context.WithCancel(context.Background())
cancel()
return ctx
}
type fakeExitWaitClock struct {
now time.Time
sleeps int
}
func (clock *fakeExitWaitClock) Now() time.Time { return clock.now }
func (clock *fakeExitWaitClock) Wait(ctx context.Context, duration time.Duration) error {
if err := ctx.Err(); err != nil {
return err
}
clock.sleeps++
clock.now = clock.now.Add(duration)
return nil
}
type snapshotItem struct {
path string
err error