Fix server file refresh pending state
This commit is contained in:
@@ -98,6 +98,52 @@ func TestCoreServiceRunJobClaimNoJob(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceRunJobClaimAllowsServerFileCapabilityWithoutDeclaration(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
instance, err := svc.CreateServerInstance(domain.ServerInstance{
|
||||
ID: "server-file-claim",
|
||||
PluginID: plugin.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Name: "File Claim Server",
|
||||
State: domain.ServerInstanceStateRunning,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create server instance: %v", err)
|
||||
}
|
||||
helloRequest := validRunControlHello()
|
||||
helloRequest.CapabilityReport.Capabilities = []string{"control.hello", "control.heartbeat", "process.start"}
|
||||
helloRequest.CapabilityReport.Fingerprint = "cap-file-claim-no-list"
|
||||
hello, err := svc.RegisterRunHello(helloRequest)
|
||||
if err != nil {
|
||||
t.Fatalf("register run hello: %v", err)
|
||||
}
|
||||
_, err = svc.CreateJob(domain.Job{
|
||||
ID: "job-file-list",
|
||||
ServerInstanceID: instance.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Capability: domain.JobCapabilityFilesList,
|
||||
TargetKey: "server-root",
|
||||
IdempotencyKey: "idem-file-list",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create file list job: %v", err)
|
||||
}
|
||||
|
||||
claim, err := svc.ClaimRunJob(domain.RunJobClaim{
|
||||
RunEndpointID: endpoint.ID,
|
||||
SessionToken: hello.SessionToken,
|
||||
Capabilities: []string{"process.start"},
|
||||
Capacity: domain.RunCapacity{MaxJobs: 4},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("claim file list job: %v", err)
|
||||
}
|
||||
if !claim.Accepted || !claim.HasJob || claim.Job.JobID != "job-file-list" || claim.Job.Capability != domain.JobCapabilityFilesList {
|
||||
t.Fatalf("expected file job claim without files.list declaration, got %+v", claim)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceRunJobRejectsInvalidSessionAndLease(t *testing.T) {
|
||||
svc, sessionToken := newRegisteredRunJobService(t)
|
||||
createQueuedRunJob(t, svc, "job-1", "idem-1")
|
||||
|
||||
@@ -970,6 +970,35 @@ func TestPluginFileWorkspaceDoesNotConstrainServerFileDispatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerFileListReportsFailedRuntimeRefresh(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
ownerSession := createServiceUserAndLogin(t, svc, domain.User{ID: "user-file-list-failure", DisplayName: "File List Failure", Email: "file-list-failure@example.test", Roles: []string{"server-owner"}, PasswordHash: "secret-password"})
|
||||
instance, err := svc.CreateServerInstanceForSession(ownerSession, domain.ServerInstance{ID: "server-file-list-failure", PluginID: plugin.ID, RunEndpointID: endpoint.ID, Name: "File List Failure Server", State: domain.ServerInstanceStateRunning})
|
||||
if err != nil {
|
||||
t.Fatalf("create server: %v", err)
|
||||
}
|
||||
createCompleteRuntimeBinding(t, svc, instance, "local")
|
||||
|
||||
refresh, err := svc.RefreshServerFileListForSession(ownerSession, domain.ServerFileListRequest{ServerInstanceID: instance.ID, DirectoryKey: "server-root", IdempotencyKey: "idem-file-list-failure"})
|
||||
if err != nil || refresh.State != "pending" || refresh.Job.ID == "" {
|
||||
t.Fatalf("refresh file list: result=%+v err=%v", refresh, err)
|
||||
}
|
||||
failedJob := refresh.Job
|
||||
failedJob.State = domain.JobStateFailed
|
||||
failedJob.Progress = domain.JobProgress{Percent: 100, Message: "executor does not support files.list"}
|
||||
failedJob.TerminalAt = fixedTime.Add(2 * time.Minute)
|
||||
failedJob.UpdatedAt = failedJob.TerminalAt
|
||||
if err := svc.store.Jobs().Update(failedJob); err != nil {
|
||||
t.Fatalf("update failed file list job: %v", err)
|
||||
}
|
||||
|
||||
list, err := svc.ListServerFilesForSession(ownerSession, domain.ServerFileListRequest{ServerInstanceID: instance.ID, DirectoryKey: "server-root"})
|
||||
if err != nil || list.State != "failed" || list.Job.ID != failedJob.ID || !strings.Contains(list.Reason, "executor does not support files.list") {
|
||||
t.Fatalf("expected failed file list state, list=%+v err=%v", list, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeclaredFileReadSnapshotProjectionStatesAndRedaction(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
|
||||
@@ -99,12 +99,19 @@ func (svc *CoreService) ListServerFilesForSession(sessionID string, request doma
|
||||
if parseErr == nil {
|
||||
return domain.CopyServerFileListResult(domain.ServerFileListResult{ServerInstanceID: ctx.Instance.ID, PluginID: ctx.Plugin.ID, DirectoryKey: request.DirectoryKey, Path: request.Path, State: "ready", Entries: filterServerFileEntries(entries, request.Query), Job: latest, RefreshedAt: latest.TerminalAt}), nil
|
||||
}
|
||||
entries = filterServerFileEntries(serverFileEntriesFromDeclaredWorkspace(ctx.Workspace, request.DirectoryKey), request.Query)
|
||||
return domain.CopyServerFileListResult(domain.ServerFileListResult{ServerInstanceID: ctx.Instance.ID, PluginID: ctx.Plugin.ID, DirectoryKey: request.DirectoryKey, Path: request.Path, State: "failed", Entries: entries, Job: latest, RefreshedAt: latest.TerminalAt, Reason: "Run 返回的文件列表无法解析。"}), nil
|
||||
}
|
||||
state := "declared"
|
||||
reason := "展示服务器文件缓存;打开文件标签时会自动读取 Run 实时目录。"
|
||||
if hasLatest && !isTerminalJobState(latest.State) {
|
||||
state = "pending"
|
||||
reason = "Run 正在刷新目录。"
|
||||
if hasLatest {
|
||||
if !isTerminalJobState(latest.State) {
|
||||
state = "pending"
|
||||
reason = "Run 正在刷新目录。"
|
||||
} else if latest.State == domain.JobStateFailed || latest.State == domain.JobStateCancelled {
|
||||
state = "failed"
|
||||
reason = serverFileListJobFailureReason(latest)
|
||||
}
|
||||
}
|
||||
entries := filterServerFileEntries(serverFileEntriesFromDeclaredWorkspace(ctx.Workspace, request.DirectoryKey), request.Query)
|
||||
if state == "declared" {
|
||||
@@ -113,6 +120,24 @@ func (svc *CoreService) ListServerFilesForSession(sessionID string, request doma
|
||||
return domain.CopyServerFileListResult(domain.ServerFileListResult{ServerInstanceID: ctx.Instance.ID, PluginID: ctx.Plugin.ID, DirectoryKey: request.DirectoryKey, Path: request.Path, State: state, Entries: entries, Job: latest, RefreshedAt: latest.TerminalAt, Reason: reason}), nil
|
||||
}
|
||||
|
||||
func serverFileListJobFailureReason(job domain.Job) string {
|
||||
prefix := "Run 文件目录刷新失败"
|
||||
if job.State == domain.JobStateCancelled {
|
||||
prefix = "Run 文件目录刷新已取消"
|
||||
}
|
||||
detail := strings.TrimSpace(job.CancelReason)
|
||||
if detail == "" {
|
||||
detail = strings.TrimSpace(job.Progress.Message)
|
||||
}
|
||||
if detail == "" {
|
||||
detail = strings.TrimSpace(job.ExecutionResult.Summary)
|
||||
}
|
||||
if detail == "" {
|
||||
return prefix + "。"
|
||||
}
|
||||
return prefix + ":" + detail
|
||||
}
|
||||
|
||||
func (svc *CoreService) RefreshServerFileListForSession(sessionID string, request domain.ServerFileListRequest) (domain.ServerFileListResult, error) {
|
||||
request = normalizeServerFileListRequest(request)
|
||||
if request.IdempotencyKey == "" {
|
||||
|
||||
Reference in New Issue
Block a user