package proxmox import ( "context" "errors" "net/http" "strings" "testing" "time" ) const testUPID = "UPID:demo-felhom:00026454:004E3431:6A265E53:vzsnapshot:9001:root@pam:" // fastWait keeps tests quick. var fastWait = WaitOptions{Interval: time.Millisecond, MaxInterval: 2 * time.Millisecond, Timeout: time.Second} func TestWaitTask_RunningThenOK(t *testing.T) { var n int d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) { n++ if n == 1 { return jsonResp(200, `{"data":{"upid":"`+testUPID+`","status":"running"}}`), nil } return jsonResp(200, `{"data":{"upid":"`+testUPID+`","status":"stopped","exitstatus":"OK"}}`), nil }} st, err := newTestClient(d).WaitTask(context.Background(), testUPID, fastWait) if err != nil { t.Fatalf("WaitTask: %v", err) } if !st.OK() { t.Errorf("status not OK: %+v", st) } } func TestWaitTask_FailedSurfacesPrivilege(t *testing.T) { // vzdump against an unauthorized vmid: 200+UPID, then the 403 in exitstatus. d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) { if strings.Contains(r.URL.Path, "/log") { return jsonResp(200, `{"data":[{"n":1,"t":"TASK ERROR: 403 Permission check failed (/vms/9000, VM.Backup)"}]}`), nil } return jsonResp(200, `{"data":{"upid":"`+testUPID+`","status":"stopped","exitstatus":"403 Permission check failed (/vms/9000, VM.Backup)"}}`), nil }} _, err := newTestClient(d).WaitTask(context.Background(), testUPID, fastWait) var te *TaskError if !errors.As(err, &te) { t.Fatalf("want *TaskError, got %T: %v", err, err) } if te.Privilege != "VM.Backup" { t.Errorf("privilege = %q, want VM.Backup", te.Privilege) } if te.DeniedPath != "/vms/9000" { t.Errorf("denied path = %q", te.DeniedPath) } if len(te.LogTail) == 0 { t.Errorf("expected a log tail") } } func TestWaitTask_Timeout(t *testing.T) { d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) { return jsonResp(200, `{"data":{"upid":"`+testUPID+`","status":"running"}}`), nil }} opts := WaitOptions{Interval: time.Millisecond, MaxInterval: time.Millisecond, Timeout: 30 * time.Millisecond} _, err := newTestClient(d).WaitTask(context.Background(), testUPID, opts) if err == nil || !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("want deadline-exceeded, got %v", err) } } func TestWaitTask_CtxCancel(t *testing.T) { d := &mockDoer{fn: func(r *http.Request) (*http.Response, error) { return jsonResp(200, `{"data":{"upid":"`+testUPID+`","status":"running"}}`), nil }} ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(20 * time.Millisecond); cancel() }() opts := WaitOptions{Interval: time.Millisecond, MaxInterval: time.Millisecond, Timeout: time.Minute} _, err := newTestClient(d).WaitTask(ctx, testUPID, opts) if err == nil || !errors.Is(err, context.Canceled) { t.Fatalf("want canceled, got %v", err) } }