From 2845ba4e2502341af6356ecae33da0d8f558db10 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 6 Jun 2017 11:30:45 -0700 Subject: [PATCH 1/4] Rename scheduling error to failure info --- .../job/browse/job-list.component.ts | 8 +-- .../job-error-display.component.ts | 4 +- .../error-display/job-error-display.html | 12 ++--- .../display/task-list-display.component.ts | 6 +-- .../sub-task-display-list.component.ts | 6 +-- .../sub-task-properties.component.ts | 4 +- .../sub-tasks/sub-task-properties.html | 10 ++-- .../details/task-configuration.component.ts | 2 +- .../task/details/task-configuration.html | 2 +- ...decorator.ts => failure-info-decorator.ts} | 6 +-- app/models/decorators/index.ts | 2 +- .../job-execution-info-decorator.ts | 6 +-- app/models/decorators/sub-task-decorator.ts | 6 +-- .../task-execution-info-decorator.ts | 6 +-- .../{scheduling-error.ts => failure-info.ts} | 10 ++-- app/models/index.ts | 2 +- app/models/job-execution-information.ts | 6 +-- app/models/subtask-information.ts | 53 ++++++++++--------- app/models/task-execution-information.ts | 35 ++++++++---- app/models/task-exit-conditions.ts | 6 +-- .../job-error-display.component.spec.ts | 2 +- test/fixture.ts | 4 +- 22 files changed, 107 insertions(+), 91 deletions(-) rename app/models/decorators/{scheduling-error-decorator.ts => failure-info-decorator.ts} (88%) rename app/models/{scheduling-error.ts => failure-info.ts} (72%) diff --git a/app/components/job/browse/job-list.component.ts b/app/components/job/browse/job-list.component.ts index e0254368e9..d5eedc1e9c 100644 --- a/app/components/job/browse/job-list.component.ts +++ b/app/components/job/browse/job-list.component.ts @@ -12,7 +12,7 @@ import { QuickListComponent, QuickListItemStatus } from "app/components/base/qui import { ListOrTableBase } from "app/components/base/selectable-list"; import { TableComponent } from "app/components/base/table"; import { Job, JobState } from "app/models"; -import { SchedulingErrorDecorator } from "app/models/decorators"; +import { FailureInfoDecorator } from "app/models/decorators"; import { JobService } from "app/services"; import { RxListProxy } from "app/services/core"; import { Filter } from "app/utils/filter-builder"; @@ -91,7 +91,7 @@ export class JobListComponent extends ListOrTableBase implements OnInit, OnDestr } public jobStatus(job: Job): QuickListItemStatus { - if (job.executionInfo && job.executionInfo.schedulingError) { + if (job.executionInfo && job.executionInfo.failureInfo) { return QuickListItemStatus.warning; } else { switch (job.state) { @@ -112,8 +112,8 @@ export class JobListComponent extends ListOrTableBase implements OnInit, OnDestr } public jobStatusText(job: Job): string { - if (job.executionInfo && job.executionInfo.schedulingError) { - return new SchedulingErrorDecorator(job.executionInfo.schedulingError).summary; + if (job.executionInfo && job.executionInfo.failureInfo) { + return new FailureInfoDecorator(job.executionInfo.failureInfo).summary; } else { switch (job.state) { case JobState.completed: diff --git a/app/components/job/details/error-display/job-error-display.component.ts b/app/components/job/details/error-display/job-error-display.component.ts index 2fda17cfd7..bb9b78f939 100644 --- a/app/components/job/details/error-display/job-error-display.component.ts +++ b/app/components/job/details/error-display/job-error-display.component.ts @@ -23,9 +23,9 @@ export class JobErrorDisplayComponent { return this.job && this.job.executionInfo; } - public get schedulingError() { + public get failureInfo() { const info = this.executionInfo; - return info && info.schedulingError; + return info && info.failureInfo; } public get jobFailed() { diff --git a/app/components/job/details/error-display/job-error-display.html b/app/components/job/details/error-display/job-error-display.html index d3dee85a76..4f301835c7 100644 --- a/app/components/job/details/error-display/job-error-display.html +++ b/app/components/job/details/error-display/job-error-display.html @@ -4,12 +4,12 @@
Job timed out after running for {{jobRunningTime}}.
- -
{{schedulingError.message}}
-
{{schedulingError.code}}
-
{{schedulingError.message}}
-
-
+ +
{{failureInfo.message}}
+
{{failureInfo.code}}
+
{{failureInfo.message}}
+
+
{{entry.name}}: {{entry.value}}
diff --git a/app/components/task/browse/display/task-list-display.component.ts b/app/components/task/browse/display/task-list-display.component.ts index 44c05716ae..8d08487f9d 100644 --- a/app/components/task/browse/display/task-list-display.component.ts +++ b/app/components/task/browse/display/task-list-display.component.ts @@ -9,7 +9,7 @@ import { ListOrTableBase } from "app/components/base/selectable-list"; import { TableComponent } from "app/components/base/table"; import { DeleteTaskDialogComponent, TerminateTaskDialogComponent } from "app/components/task/action"; import { Task, TaskState } from "app/models"; -import { SchedulingErrorDecorator } from "app/models/decorators"; +import { FailureInfoDecorator } from "app/models/decorators"; import { TaskService } from "app/services"; import { DateUtils } from "app/utils"; @@ -46,8 +46,8 @@ export class TaskListDisplayComponent extends ListOrTableBase { } public taskStatusText(task: Task): string { - if (task.executionInfo && task.executionInfo.schedulingError) { - return new SchedulingErrorDecorator(task.executionInfo.schedulingError).summary; + if (task.executionInfo && task.executionInfo.failureInfo) { + return new FailureInfoDecorator(task.executionInfo.failureInfo).summary; } else if (task.executionInfo && task.executionInfo.exitCode !== 0) { return `Task failed with exitCode: ${task.executionInfo.exitCode}`; } diff --git a/app/components/task/details/sub-tasks/sub-task-display-list.component.ts b/app/components/task/details/sub-tasks/sub-task-display-list.component.ts index 6f5b195abd..aa45be35c4 100644 --- a/app/components/task/details/sub-tasks/sub-task-display-list.component.ts +++ b/app/components/task/details/sub-tasks/sub-task-display-list.component.ts @@ -5,7 +5,7 @@ import { LoadingStatus } from "app/components/base/loading"; import { QuickListComponent, QuickListItemStatus } from "app/components/base/quick-list"; import { SelectableList } from "app/components/base/selectable-list"; import { SubtaskInformation, TaskState } from "app/models"; -import { SchedulingErrorDecorator } from "app/models/decorators"; +import { FailureInfoDecorator } from "app/models/decorators"; @Component({ selector: "bl-sub-task-display-list", @@ -43,8 +43,8 @@ export class SubTaskDisplayListComponent extends SelectableList { } public taskStatusText(task: SubtaskInformation): string { - if (task.schedulingError) { - return new SchedulingErrorDecorator(task.schedulingError).summary; + if (task.failureInfo) { + return new FailureInfoDecorator(task.failureInfo).summary; } else if (task.exitCode !== 0) { return `Subtask failed with exitCode: ${task.exitCode}`; } diff --git a/app/components/task/details/sub-tasks/sub-task-properties.component.ts b/app/components/task/details/sub-tasks/sub-task-properties.component.ts index 9099e92f6d..d196d748d8 100644 --- a/app/components/task/details/sub-tasks/sub-task-properties.component.ts +++ b/app/components/task/details/sub-tasks/sub-task-properties.component.ts @@ -12,11 +12,11 @@ export class SubTaskPropertiesComponent { @Input() public set task(value: SubtaskInformation) { this.decorator = new SubTaskDecorator(value || {} as any); - this.schedulingError = this.decorator.schedulingError || {}; + this.failureInfo = this.decorator.failureInfo || {}; this.nodeInfo = this.decorator.nodeInfo || {}; } public decorator: SubTaskDecorator; - public schedulingError: any; + public failureInfo: any; public nodeInfo: any; } diff --git a/app/components/task/details/sub-tasks/sub-task-properties.html b/app/components/task/details/sub-tasks/sub-task-properties.html index 257a5548eb..7aa211b06a 100644 --- a/app/components/task/details/sub-tasks/sub-task-properties.html +++ b/app/components/task/details/sub-tasks/sub-task-properties.html @@ -19,10 +19,10 @@ - - - - - + + + + + diff --git a/app/components/task/details/task-configuration.component.ts b/app/components/task/details/task-configuration.component.ts index 7edeea1446..aa4600be0b 100644 --- a/app/components/task/details/task-configuration.component.ts +++ b/app/components/task/details/task-configuration.component.ts @@ -79,7 +79,7 @@ export class TaskConfigurationComponent { this.exitConditionData = { noAction, terminateJob, - schedulingError: this._jobActionString(this._task.exitConditions.schedulingError), + failureInfo: this._jobActionString(this._task.exitConditions.failureInfo), default: this._jobActionString(this._task.exitConditions.default), }; } diff --git a/app/components/task/details/task-configuration.html b/app/components/task/details/task-configuration.html index 5a245e137d..b5ec699183 100644 --- a/app/components/task/details/task-configuration.html +++ b/app/components/task/details/task-configuration.html @@ -76,7 +76,7 @@ - + diff --git a/app/models/decorators/scheduling-error-decorator.ts b/app/models/decorators/failure-info-decorator.ts similarity index 88% rename from app/models/decorators/scheduling-error-decorator.ts rename to app/models/decorators/failure-info-decorator.ts index b6ff6d73aa..3d0a0d457b 100644 --- a/app/models/decorators/scheduling-error-decorator.ts +++ b/app/models/decorators/failure-info-decorator.ts @@ -1,7 +1,7 @@ -import { SchedulingError } from "app/models"; +import { FailureInfo } from "app/models"; import { DecoratorBase } from "app/utils/decorators"; -export class SchedulingErrorDecorator extends DecoratorBase { +export class FailureInfoDecorator extends DecoratorBase { public category: string; public code: string; public message: string; @@ -17,7 +17,7 @@ export class SchedulingErrorDecorator extends DecoratorBase { */ public exists: boolean; - constructor(error: SchedulingError) { + constructor(error: FailureInfo) { super(error); this.exists = Boolean(error && error.category); diff --git a/app/models/decorators/index.ts b/app/models/decorators/index.ts index 51cd0bbaba..6f0c9a7afb 100644 --- a/app/models/decorators/index.ts +++ b/app/models/decorators/index.ts @@ -1,6 +1,7 @@ export * from "./application-decorator"; export * from "./cloud-service-configuration-decorator"; export * from "./compute-node-info-decorator"; +export * from "./failure-info-decorator"; export * from "./image-reference-decorator"; export * from "./job-constraints-decorator"; export * from "./job-decorator"; @@ -9,7 +10,6 @@ export * from "./job-manager-task-decorator"; export * from "./job-preparation-task-decorator"; export * from "./job-release-task-decorator"; export * from "./pool-decorator"; -export * from "./scheduling-error-decorator"; export * from "./start-task.decorator"; export * from "./sub-task-decorator"; export * from "./node-decorator"; diff --git a/app/models/decorators/job-execution-info-decorator.ts b/app/models/decorators/job-execution-info-decorator.ts index abd67d04ad..ff405dc1fa 100644 --- a/app/models/decorators/job-execution-info-decorator.ts +++ b/app/models/decorators/job-execution-info-decorator.ts @@ -1,12 +1,12 @@ import { JobExecutionInformation } from "app/models"; import { DecoratorBase } from "app/utils/decorators"; -import { SchedulingErrorDecorator } from "./scheduling-error-decorator"; +import { FailureInfoDecorator } from "./failure-info-decorator"; export class JobExecutionInfoDecorator extends DecoratorBase { public startTime: string; public endTime: string; public poolId: string; - public schedulingError: SchedulingErrorDecorator; + public failureInfo: FailureInfoDecorator; public terminateReason: string; constructor(executionInfo: JobExecutionInformation) { @@ -15,7 +15,7 @@ export class JobExecutionInfoDecorator extends DecoratorBase { public startTime: string; @@ -14,7 +14,7 @@ export class SubTaskDecorator extends DecoratorBase { public previousStateTransitionTime: string; public nodeInfo: {}; - public schedulingError: {}; + public failureInfo: {}; constructor(task?: SubtaskInformation) { super(task); @@ -29,7 +29,7 @@ export class SubTaskDecorator extends DecoratorBase { this.previousStateTransitionTime = this.dateField(task.previousStateTransitionTime); this.nodeInfo = new ComputeNodeInfoDecorator(task.nodeInfo || {} as any); - this.schedulingError = new SchedulingErrorDecorator(task.schedulingError || {} as any); + this.failureInfo = new FailureInfoDecorator(task.failureInfo || {} as any); } // todo: base class ... diff --git a/app/models/decorators/task-execution-info-decorator.ts b/app/models/decorators/task-execution-info-decorator.ts index 63c6bed148..b709070434 100644 --- a/app/models/decorators/task-execution-info-decorator.ts +++ b/app/models/decorators/task-execution-info-decorator.ts @@ -1,12 +1,12 @@ import { TaskExecutionInformation } from "app/models"; import { DecoratorBase } from "app/utils/decorators"; -import { SchedulingErrorDecorator } from "./scheduling-error-decorator"; +import { FailureInfoDecorator } from "./failure-info-decorator"; export class TaskExecutionInfoDecorator extends DecoratorBase { public startTime: string; public endTime: string; public exitCode: string; - public schedulingError: SchedulingErrorDecorator; + public failureInfo: FailureInfoDecorator; public retryCount: string; public lastRetryTime: string; public requeueCount: string; @@ -18,7 +18,7 @@ export class TaskExecutionInfoDecorator extends DecoratorBase { +export class FailureInfo extends Record { @Prop() public code: string; @Prop() public category: string; @Prop() public message: string; diff --git a/app/models/index.ts b/app/models/index.ts index 71d02732da..9e1d729b82 100644 --- a/app/models/index.ts +++ b/app/models/index.ts @@ -12,6 +12,7 @@ export * from "./cloud-service-configuration"; export * from "./compute-node-information"; export * from "./constraints"; export * from "./image-reference"; +export * from "./failure-info"; export * from "./file"; export * from "./file-type"; export * from "./file-properties"; @@ -38,7 +39,6 @@ export * from "./pool"; export * from "./resize-error"; export * from "./resource-descriptor"; export * from "./resource-file"; -export * from "./scheduling-error"; export * from "./settings"; export * from "./spec-cost"; export * from "./ssh-public-key"; diff --git a/app/models/job-execution-information.ts b/app/models/job-execution-information.ts index b99f2cba16..44e7752ea0 100644 --- a/app/models/job-execution-information.ts +++ b/app/models/job-execution-information.ts @@ -1,5 +1,5 @@ import { Model, Prop, Record } from "app/core"; -import { SchedulingError, SchedulingErrorAttributes } from "./scheduling-error"; +import { FailureInfo, FailureInfoAttributes } from "./failure-info"; /** * Job terminate reason. @@ -24,7 +24,7 @@ export interface JobExecutionInformationAttributes { startTime: Date; endTime: Date; poolId: string; - schedulingError: Partial; + failureInfo: FailureInfoAttributes; terminateReason: JobTerminateReason; } @@ -36,6 +36,6 @@ export class JobExecutionInformation extends Record { + @Prop() public id: string; + @Prop() public startTime: Date; + @Prop() public endTime: Date; + @Prop() public exitCode: number; + @Prop() public state: TaskState; + @Prop() public stateTransitionTime: Date; + @Prop() public previousState: TaskState; + @Prop() public previousStateTransitionTime: Date; - public nodeInfo: ComputeNodeInformation; - public schedulingError: SchedulingError; + @Prop() public nodeInfo: ComputeNodeInformation; + @Prop() public failureInfo: FailureInfo; } diff --git a/app/models/task-execution-information.ts b/app/models/task-execution-information.ts index a544eb5178..c0d9eecfa8 100644 --- a/app/models/task-execution-information.ts +++ b/app/models/task-execution-information.ts @@ -1,15 +1,30 @@ -import { SchedulingError } from "./scheduling-error"; +import { Model, Prop, Record } from "app/core"; +import { FailureInfo, FailureInfoAttributes } from "./failure-info"; + +export interface TaskExecutionInformationAttributes { + startTime: Date; + endTime?: Date; + state: string; + taskRootDirectory?: string; + taskRootDirectoryUrl?: string; + exitCode?: number; + failureInfo?: FailureInfoAttributes; + retryCount: number; + lastRetryTime?: Date; + result?: string; +} /** * Contains information about the execution of a task in the Azure */ -export class TaskExecutionInformation { - public startTime: Date; - public endTime: Date; - public exitCode: number; - public schedulingError: SchedulingError; - public retryCount: number; - public lastRetryTime: Date; - public requeueCount: number; - public lastRequeueTime: Date; +@Model() +export class TaskExecutionInformation extends Record { + @Prop() public startTime: Date; + @Prop() public endTime: Date; + @Prop() public exitCode: number; + @Prop() public failureInfo: FailureInfo; + @Prop() public retryCount: number; + @Prop() public lastRetryTime: Date; + @Prop() public requeueCount: number; + @Prop() public lastRequeueTime: Date; } diff --git a/app/models/task-exit-conditions.ts b/app/models/task-exit-conditions.ts index ceb0e719fa..c7390b5751 100644 --- a/app/models/task-exit-conditions.ts +++ b/app/models/task-exit-conditions.ts @@ -7,21 +7,21 @@ import { JobAction } from "./job-action"; const TaskExitConditionsRecord = Record({ exitCodes: [], exitCodeRanges: [], - schedulingError: null, + failureInfo: null, default: null, }); export class TaskExitConditions extends TaskExitConditionsRecord { public exitCodes: List; public exitCodeRanges: List; - public schedulingError: ExitOptions; + public failureInfo: ExitOptions; public default: ExitOptions; constructor(data: any = {}) { super(Object.assign({}, data, ObjectUtils.compact({ exitCodes: data.exitCodes && List(data.exitCodes.map(x => new ExitCodeMapping(x))), exitCodeRanges: data.exitCodeRanges && List(data.exitCodeRanges.map(x => new ExitCodeRangeMapping(x))), - schedulingError: new ExitOptions(data.schedulingError), + failureInfo: new ExitOptions(data.failureInfo), default: new ExitOptions(data.default), }))); } diff --git a/test/app/components/job/details/error-display/job-error-display.component.spec.ts b/test/app/components/job/details/error-display/job-error-display.component.spec.ts index 6aa1aed275..ee6bd0fcae 100644 --- a/test/app/components/job/details/error-display/job-error-display.component.spec.ts +++ b/test/app/components/job/details/error-display/job-error-display.component.spec.ts @@ -119,7 +119,7 @@ describe("JobErrorDisplayComponent", () => { maxWallClockTime: moment.duration("PT2M"), }, executionInfo: { - schedulingError: { + failureInfo: { code: "InvalidAutoPoolSettings", category: "UserError", message: "Auto pool has invalid settings", diff --git a/test/fixture.ts b/test/fixture.ts index b810174b40..c2532b81e6 100644 --- a/test/fixture.ts +++ b/test/fixture.ts @@ -59,7 +59,7 @@ export const job = new FixtureFactory(Job, { endTime: new Date(2015, 5, 1, 10, 4, 31), poolId: "pool-1", terminateReason: "because i said so", - schedulingError: { + failureInfo: { category: "cat1", code: "code1", message: "this is a message", @@ -98,7 +98,7 @@ export const task = new FixtureFactory(Task, { lastRetryTime: new Date(2015, 5, 21, 0, 0, 0), requeueCount: 1, lastRequeueTime: new Date(2015, 5, 21, 0, 0, 0), - schedulingError: { + failureInfo: { category: "cat1", code: "code1", message: "this is a message", From 64dc738530e22cd0f99a7fd73ce18ce57905ec52 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 6 Jun 2017 11:51:40 -0700 Subject: [PATCH 2/4] Update messages --- .../details/task-error-display.component.ts | 55 ++++++++++++------- .../task/details/task-error-display.html | 7 ++- app/models/task.ts | 2 +- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/app/components/task/details/task-error-display.component.ts b/app/components/task/details/task-error-display.component.ts index 0e25d3bdb0..e40aeb6bdb 100644 --- a/app/components/task/details/task-error-display.component.ts +++ b/app/components/task/details/task-error-display.component.ts @@ -1,9 +1,9 @@ -import { ChangeDetectionStrategy, Component, Input } from "@angular/core"; +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from "@angular/core"; import { autobind } from "core-decorators"; import { SidebarManager } from "app/components/base/sidebar"; import { RerunTaskFormComponent } from "app/components/task/action"; -import { Task, TaskState } from "app/models"; +import { FailureInfo, Task, TaskState } from "app/models"; import { TaskService } from "app/services"; import { DateUtils, ObservableUtils } from "app/utils"; @@ -12,36 +12,33 @@ import { DateUtils, ObservableUtils } from "app/utils"; templateUrl: "task-error-display.html", changeDetection: ChangeDetectionStrategy.OnPush, }) -export class TaskErrorDisplayComponent { +export class TaskErrorDisplayComponent implements OnChanges { @Input() public jobId: string; @Input() public task: Task; + public hasCompleted: boolean = false; + public failureInfo: FailureInfo; + public code: number; + public hasFailureExitCode: boolean = false; + public errorMessage: string; + constructor( private taskService: TaskService, private sidebarManager: SidebarManager) { } - public get hasCompleted(): boolean { - return Boolean(this.task && this.task.state === TaskState.completed); - } - - public get code() { - return this.task && this.task.executionInfo && this.task.executionInfo.exitCode; - } - - public get hasFailureExitCode(): boolean { - return this.hasCompleted && this.code !== 0; - } - - public get exitCodeMessage(): string { - if (this.task.didTimeout) { - const time: any = this.task.constraints && this.task.constraints.maxWallClockTime; - return `Task timed out after running for ${DateUtils.prettyDuration(time)}`; - } else { - return `Task completed with exit code '${this.code}'`; + public ngOnChanges(changes: SimpleChanges) { + if (changes.task) { + const exec = this.task.executionInfo; + this.failureInfo = exec && exec.failureInfo; + this.hasCompleted = Boolean(this.task && this.task.state === TaskState.completed); + this.code = this.task && this.task.executionInfo && this.task.executionInfo.exitCode; + this.hasFailureExitCode = this.hasCompleted && this.code !== 0; + this._computeExitCodeMessage(); + console.log({ ...this.task.executionInfo.failureInfo }); } } @@ -59,4 +56,20 @@ export class TaskErrorDisplayComponent { ref.component.jobId = this.jobId; ref.component.setValueFromEntity(this.task); } + + private _computeExitCodeMessage() { + if (!this.failureInfo) { + this.errorMessage = ""; + return; + } + + if (this.task.didTimeout) { + const time: any = this.task.constraints && this.task.constraints.maxWallClockTime; + this.errorMessage = `Task timed out after running for ${DateUtils.prettyDuration(time)}`; + } else if (this.failureInfo.code === "FailureExitCode") { + this.errorMessage = `Task completed with exit code '${this.code}'`; + } else { + this.errorMessage = this.failureInfo.message; + } + } } diff --git a/app/components/task/details/task-error-display.html b/app/components/task/details/task-error-display.html index eaf109293d..69c47664f4 100644 --- a/app/components/task/details/task-error-display.html +++ b/app/components/task/details/task-error-display.html @@ -1,4 +1,9 @@ - + + +
{{failureInfo.code}}
+
+
{{errorMessage}}
diff --git a/app/models/task.ts b/app/models/task.ts index 38ad82d251..e9c60c914d 100644 --- a/app/models/task.ts +++ b/app/models/task.ts @@ -82,7 +82,7 @@ export class Task extends TaskRecord { public get didTimeout() { const info = this.executionInfo; const constraints = this.constraints; - if (!(info && info.exitCode && constraints && constraints.maxWallClockTime)) { + if (!(info && info.failureInfo && info.exitCode && constraints && constraints.maxWallClockTime)) { return false; } if (info.exitCode === 0) { From 448ae7c03148682c6e557d879945fe08429736c2 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 6 Jun 2017 12:41:43 -0700 Subject: [PATCH 3/4] Remove console.log --- app/components/task/details/task-error-display.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/task/details/task-error-display.component.ts b/app/components/task/details/task-error-display.component.ts index e40aeb6bdb..6098dd8906 100644 --- a/app/components/task/details/task-error-display.component.ts +++ b/app/components/task/details/task-error-display.component.ts @@ -38,7 +38,6 @@ export class TaskErrorDisplayComponent implements OnChanges { this.code = this.task && this.task.executionInfo && this.task.executionInfo.exitCode; this.hasFailureExitCode = this.hasCompleted && this.code !== 0; this._computeExitCodeMessage(); - console.log({ ...this.task.executionInfo.failureInfo }); } } From 5cde2adb29dbb14aa9cd37d424328e3f7d897247 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 6 Jun 2017 13:43:46 -0700 Subject: [PATCH 4/4] fix tests --- .../details/task-error-display.component.ts | 20 +++++++++++++------ .../task-error-display.component.spec.ts | 17 +++++++++++++++- .../task-timeline.component.spec.ts | 4 ++++ test/app/models/task.spec.ts | 17 ++++++++++++---- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/app/components/task/details/task-error-display.component.ts b/app/components/task/details/task-error-display.component.ts index 6098dd8906..05c2338f65 100644 --- a/app/components/task/details/task-error-display.component.ts +++ b/app/components/task/details/task-error-display.component.ts @@ -32,12 +32,20 @@ export class TaskErrorDisplayComponent implements OnChanges { public ngOnChanges(changes: SimpleChanges) { if (changes.task) { - const exec = this.task.executionInfo; - this.failureInfo = exec && exec.failureInfo; - this.hasCompleted = Boolean(this.task && this.task.state === TaskState.completed); - this.code = this.task && this.task.executionInfo && this.task.executionInfo.exitCode; - this.hasFailureExitCode = this.hasCompleted && this.code !== 0; - this._computeExitCodeMessage(); + if (this.task) { + + const exec = this.task.executionInfo; + this.failureInfo = exec && exec.failureInfo; + this.hasCompleted = Boolean(this.task && this.task.state === TaskState.completed); + this.code = exec && this.task.executionInfo.exitCode; + this.hasFailureExitCode = this.hasCompleted && this.code !== 0; + this._computeExitCodeMessage(); + } else { + this.failureInfo = null; + this.code = null; + this.hasFailureExitCode = false; + this.errorMessage = ""; + } } } diff --git a/test/app/components/task/details/task-error-display.component.spec.ts b/test/app/components/task/details/task-error-display.component.spec.ts index 9bcde92ac2..10698b9d9c 100644 --- a/test/app/components/task/details/task-error-display.component.spec.ts +++ b/test/app/components/task/details/task-error-display.component.spec.ts @@ -54,6 +54,11 @@ describe("TaskErrorDisplayComponent", () => { testComponent.task = new Task({ state: TaskState.completed, executionInfo: { + failureInfo: { + category: "UserError", + code: "FailureExitCode", + message: "Task has wrong exit code", + }, exitCode: 1, }, }); @@ -69,11 +74,21 @@ describe("TaskErrorDisplayComponent", () => { expect(fixture.debugElement.queryAll(By.css("bl-banner")).length).toBe(1); }); - it("Should show the code and message", () => { + it("Should contain the error code", () => { + const banner = fixture.debugElement.query(By.css("bl-banner")); + expect(banner.nativeElement.textContent).toContain("FailureExitCode"); + }); + + it("Should custom message", () => { const banner = fixture.debugElement.query(By.css("bl-banner")); expect(banner.nativeElement.textContent).toContain("Task completed with exit code '1'"); }); + it("Should not show the failure info message", () => { + const banner = fixture.debugElement.query(By.css("bl-banner")); + expect(banner.nativeElement.textContent).not.toContain("Task has wrong exit code"); + }); + it("should propose increase quota as a first fix", () => { const banner = fixture.debugElement.query(By.css("bl-banner")).componentInstance; expect(banner.fixMessage).toContain("Rerun task"); diff --git a/test/app/components/task/details/task-lifetime/task-timeline.component.spec.ts b/test/app/components/task/details/task-lifetime/task-timeline.component.spec.ts index 3e45d114e3..0f0ea70262 100644 --- a/test/app/components/task/details/task-lifetime/task-timeline.component.spec.ts +++ b/test/app/components/task/details/task-lifetime/task-timeline.component.spec.ts @@ -28,6 +28,10 @@ function createTask(state: string, timeout = "PT6M") { endTime: moment().subtract(20, "minutes").toDate(), retryCount: 3, exitCode: -3, + failureInfo: { + category: "UserError", + code: "TaskEnded", + }, }, constraints: { maxWallClockTime: moment.duration(timeout), diff --git a/test/app/models/task.spec.ts b/test/app/models/task.spec.ts index 5ed31d8d60..493dc5ac45 100644 --- a/test/app/models/task.spec.ts +++ b/test/app/models/task.spec.ts @@ -2,15 +2,24 @@ import * as moment from "moment"; import { Task } from "app/models"; -function createTask(exitCode: number, startTime: Date, endTime: Date, maxWallClockTime = "PT4M") { +function createTask(exitCode: number, startTime: Date, endTime: Date, hasFailureInfo = false) { + let failureInfo = null; + + if (hasFailureInfo) { + failureInfo = { + category: "UserError", + code: "TaskEnded", + }; + } return new Task({ executionInfo: { startTime, endTime, exitCode, + failureInfo, }, constraints: { - maxWallClockTime: moment.duration(maxWallClockTime), + maxWallClockTime: moment.duration("PT4M"), }, }); } @@ -34,13 +43,13 @@ describe("Task Model", () => { it("should return false if runnnig time is less than clock time", () => { const current = moment(); - const task = createTask(0, current.clone().subtract(3, "minute").toDate(), current.toDate()); + const task = createTask(0, current.clone().subtract(3, "minute").toDate(), current.toDate(), true); expect(task.didTimeout).toBe(false); }); it("should return true if runnnig time is more than clock time", () => { const current = moment(); - const task = createTask(-10, current.clone().subtract(5, "minute").toDate(), current.toDate()); + const task = createTask(-10, current.clone().subtract(5, "minute").toDate(), current.toDate(), true); expect(task.didTimeout).toBe(true); }); });