|
| 1 | +import { it, expect } from 'vitest'; |
| 2 | +import { extractJobErrorParts, extractRelevantJobError } from '$lib/common/job_utilities.js'; |
| 3 | + |
| 4 | +const completeTracebackError = `TASK ERROR:Task id: 15 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 5 | +TRACEBACK: |
| 6 | +2024-01-29 16:52:02,328; INFO; START create_ome_zarr task |
| 7 | +Traceback (most recent call last): |
| 8 | + File "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/lib/python3.10/site-packages/fractal_tasks_core/tasks/create_ome_zarr.py", line 470, in <module> |
| 9 | + run_fractal_task( |
| 10 | + File "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/lib/python3.10/site-packages/fractal_tasks_core/tasks/_utils.py", line 79, in run_fractal_task |
| 11 | + metadata_update = task_function(**pars) |
| 12 | + File "pydantic/decorator.py", line 40, in pydantic.decorator.validate_arguments.validate.wrapper_function |
| 13 | + File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__ |
| 14 | +pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr |
| 15 | +allowed_channels |
| 16 | + field required (type=value_error.missing) |
| 17 | +`; |
| 18 | + |
| 19 | +const shortTracebackError = `TASK ERROR:Task id: 20 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 20 | +TRACEBACK: |
| 21 | +Command "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/bin/python" is not valid. Hint: make sure that it is executable.`; |
| 22 | + |
| 23 | +it('detect parts of a workflow task error message with complete traceback', () => { |
| 24 | + const parts = extractJobErrorParts(completeTracebackError); |
| 25 | + expect(parts.length).eq(3); |
| 26 | + expect(parts[0].text).eq( |
| 27 | + 'TASK ERROR:Task id: 15 (Create OME-Zarr structure), e.workflow_task_order=0' |
| 28 | + ); |
| 29 | + expect(parts[0].highlight).eq(true); |
| 30 | + expect(parts[1].text).eq(`TRACEBACK: |
| 31 | +2024-01-29 16:52:02,328; INFO; START create_ome_zarr task |
| 32 | +Traceback (most recent call last): |
| 33 | + File "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/lib/python3.10/site-packages/fractal_tasks_core/tasks/create_ome_zarr.py", line 470, in <module> |
| 34 | + run_fractal_task( |
| 35 | + File "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/lib/python3.10/site-packages/fractal_tasks_core/tasks/_utils.py", line 79, in run_fractal_task |
| 36 | + metadata_update = task_function(**pars) |
| 37 | + File "pydantic/decorator.py", line 40, in pydantic.decorator.validate_arguments.validate.wrapper_function |
| 38 | + File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__`); |
| 39 | + expect(parts[1].highlight).eq(false); |
| 40 | + expect(parts[2].text) |
| 41 | + .eq(`pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr |
| 42 | +allowed_channels |
| 43 | + field required (type=value_error.missing)`); |
| 44 | + expect(parts[2].highlight).eq(true); |
| 45 | +}); |
| 46 | + |
| 47 | +it('detect parts of a workflow task error message with short traceback', () => { |
| 48 | + const parts = extractJobErrorParts(shortTracebackError); |
| 49 | + expect(parts.length).eq(3); |
| 50 | + expect(parts[0].text).eq( |
| 51 | + 'TASK ERROR:Task id: 20 (Create OME-Zarr structure), e.workflow_task_order=0' |
| 52 | + ); |
| 53 | + expect(parts[0].highlight).eq(true); |
| 54 | + expect(parts[1].text).eq('TRACEBACK:'); |
| 55 | + expect(parts[1].highlight).eq(false); |
| 56 | + expect(parts[2].text).eq( |
| 57 | + `Command "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/bin/python" is not valid. Hint: make sure that it is executable.` |
| 58 | + ); |
| 59 | + expect(parts[2].highlight).eq(true); |
| 60 | +}); |
| 61 | + |
| 62 | +it('detect parts of a workflow task error message without traceback', () => { |
| 63 | + const parts = extractJobErrorParts('foo'); |
| 64 | + expect(parts.length).eq(1); |
| 65 | + expect(parts[0].text).eq('foo'); |
| 66 | + expect(parts[0].highlight).eq(false); |
| 67 | +}); |
| 68 | + |
| 69 | +it('extract relevant part of a workflow task error message with complete traceback', () => { |
| 70 | + const relevantError = extractRelevantJobError(completeTracebackError); |
| 71 | + expect(relevantError) |
| 72 | + .eq(`TASK ERROR:Task id: 15 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 73 | +pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr |
| 74 | +allowed_channels |
| 75 | + field required (type=value_error.missing)`); |
| 76 | +}); |
| 77 | + |
| 78 | +it('extract relevant part of a workflow task error message with short traceback', () => { |
| 79 | + const relevantError = extractRelevantJobError(shortTracebackError); |
| 80 | + expect(relevantError).eq( |
| 81 | + `TASK ERROR:Task id: 20 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 82 | +Command "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/bin/python" is not valid. Hint: make sure that it is executable.` |
| 83 | + ); |
| 84 | +}); |
| 85 | + |
| 86 | +it('extract relevant part of a workflow task error message without traceback', () => { |
| 87 | + const relevantError = extractRelevantJobError('foo'); |
| 88 | + expect(relevantError).eq('foo'); |
| 89 | +}); |
| 90 | + |
| 91 | +it('extract relevant part of a workflow task error with max lines reached', () => { |
| 92 | + const relevantError = extractRelevantJobError(completeTracebackError, 3); |
| 93 | + expect(relevantError) |
| 94 | + .eq(`TASK ERROR:Task id: 15 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 95 | +pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr |
| 96 | +allowed_channels |
| 97 | +[...]`); |
| 98 | +}); |
| 99 | + |
| 100 | +it('extract relevant part of a workflow task error with max lines not reached', () => { |
| 101 | + const relevantError = extractRelevantJobError(completeTracebackError, 4); |
| 102 | + expect(relevantError) |
| 103 | + .eq(`TASK ERROR:Task id: 15 (Create OME-Zarr structure), e.workflow_task_order=0 |
| 104 | +pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr |
| 105 | +allowed_channels |
| 106 | + field required (type=value_error.missing)`); |
| 107 | +}); |
| 108 | + |
| 109 | +it('detect parts of a workflow JobExecutionError', () => { |
| 110 | + const error = `JOB ERROR: |
| 111 | +TRACEBACK: |
| 112 | +JobExecutionError |
| 113 | +
|
| 114 | +Job cancelled due to executor shutdown.`; |
| 115 | + const parts = extractJobErrorParts(error); |
| 116 | + expect(parts.length).eq(3); |
| 117 | + expect(parts[0].text).eq('JOB ERROR:'); |
| 118 | + expect(parts[0].highlight).eq(true); |
| 119 | + expect(parts[1].text).eq('TRACEBACK:'); |
| 120 | + expect(parts[1].highlight).eq(false); |
| 121 | + expect(parts[2].text).eq(`JobExecutionError |
| 122 | +
|
| 123 | +Job cancelled due to executor shutdown.`); |
| 124 | + expect(parts[2].highlight).eq(true); |
| 125 | +}); |
| 126 | + |
| 127 | +it('detect parts of an error with multiple tracebacks', () => { |
| 128 | + const log = `TASK ERROR:Task id: 1400 (Measure Features), e.workflow_task_order=10 |
| 129 | +TRACEBACK: |
| 130 | +Traceback (most recent call last): |
| 131 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 408, in call_single_parallel_task |
| 132 | + raise e |
| 133 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 401, in call_single_parallel_task |
| 134 | + _call_command_wrapper( |
| 135 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 184, in _call_command_wrapper |
| 136 | + raise TaskExecutionError(err) |
| 137 | +fractal_server.app.runner.common.TaskExecutionError: 2024-02-05 15:56:19,240; INFO; START measure_features task |
| 138 | +Traceback (most recent call last): |
| 139 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/zarr/core.py", line 252, in _load_metadata_nosync |
| 140 | + meta_bytes = self._store[mkey] |
| 141 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/zarr/storage.py", line 1113, in __getitem__ |
| 142 | + raise KeyError(key) |
| 143 | +KeyError: '.zarray' |
| 144 | +
|
| 145 | +During handling of the above exception, another exception occurred: |
| 146 | +
|
| 147 | +Traceback (most recent call last): |
| 148 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/apx_fractal_task_collection/measure_features.py", line 299, in <module> |
| 149 | + run_fractal_task( |
| 150 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/fractal_tasks_core/tasks/_utils.py", line 79, in run_fractal_task |
| 151 | + metadata_update = task_function(**pars) |
| 152 | + File "pydantic/decorator.py", line 40, in pydantic.decorator.validate_arguments.validate.wrapper_function |
| 153 | + File "pydantic/decorator.py", line 134, in pydantic.decorator.ValidatedFunction.call |
| 154 | + File "pydantic/decorator.py", line 206, in pydantic.decorator.ValidatedFunction.execute |
| 155 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/apx_fractal_task_collection/measure_features.py", line 211, in measure_features |
| 156 | + label_image = da.from_zarr( |
| 157 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/dask/array/core.py", line 3599, in from_zarr |
| 158 | + z = zarr.Array(store, read_only=True, path=component, **kwargs) |
| 159 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/zarr/core.py", line 224, in __init__ |
| 160 | + self._load_metadata() |
| 161 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/zarr/core.py", line 243, in _load_metadata |
| 162 | + self._load_metadata_nosync() |
| 163 | + File "/redacted/fractal-demos/examples/server/FRACTAL_TASKS_DIR/.fractal/apx_fractal_task_collection0.1.1/venv/lib/python3.10/site-packages/zarr/core.py", line 254, in _load_metadata_nosync |
| 164 | + raise ArrayNotFoundError(self._path) |
| 165 | +zarr.errors.ArrayNotFoundError: array not found at path %r' ''`; |
| 166 | + const parts = extractJobErrorParts(log); |
| 167 | + expect(parts.length).eq(3); |
| 168 | + expect(parts[0].text).eq('TASK ERROR:Task id: 1400 (Measure Features), e.workflow_task_order=10'); |
| 169 | + expect(parts[0].highlight).eq(true); |
| 170 | + expect(parts[1].highlight).eq(false); |
| 171 | + expect(parts[2].text).eq("zarr.errors.ArrayNotFoundError: array not found at path %r' ''"); |
| 172 | + expect(parts[2].highlight).eq(true); |
| 173 | +}); |
| 174 | + |
| 175 | +it('detect parts of an unknown error without traceback', () => { |
| 176 | + const log = `UNKNOWN ERROR |
| 177 | +Original error: something went really wrong`; |
| 178 | + const parts = extractJobErrorParts(log); |
| 179 | + expect(parts.length).eq(2); |
| 180 | + expect(parts[0].text).eq('UNKNOWN ERROR'); |
| 181 | + expect(parts[0].highlight).eq(true); |
| 182 | + expect(parts[1].text).eq('Original error: something went really wrong'); |
| 183 | + expect(parts[1].highlight).eq(false); |
| 184 | +}); |
| 185 | + |
| 186 | +it('detect parts of an unknown error with traceback', () => { |
| 187 | + const log = `UNKNOWN ERROR |
| 188 | +Original error: Traceback (most recent call last): |
| 189 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 281, in call_single_task |
| 190 | + raise e |
| 191 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 274, in call_single_task |
| 192 | + _call_command_wrapper( |
| 193 | + File "/redacted/anaconda3/envs/fractal-server-1.4.0/lib/python3.10/site-packages/fractal_server/app/runner/_common.py", line 184, in _call_command_wrapper |
| 194 | + raise TaskExecutionError(err) |
| 195 | +fractal_server.app.runner.common.TaskExecutionError: Traceback (most recent call last): |
| 196 | + File "/redacted/apx_fractal_task_collection/src/apx_fractal_task_collection/multiplexed_pixel_clustering.py", line 26, in <module> |
| 197 | + from sklearn.preprocessing import StandardScalerfrom, PowerTransformer |
| 198 | +ImportError: cannot import name 'StandardScalerfrom' from 'sklearn.preprocessing' (/redacted/.conda/envs/custom_fractal_task_collection/lib/python3.10/site-packages/sklearn/preprocessing/__init__.py)`; |
| 199 | + const parts = extractJobErrorParts(log); |
| 200 | + expect(parts.length).eq(3); |
| 201 | + expect(parts[0].text).eq('UNKNOWN ERROR'); |
| 202 | + expect(parts[0].highlight).eq(true); |
| 203 | + expect(parts[1].highlight).eq(false); |
| 204 | + expect(parts[2].text).eq( |
| 205 | + "ImportError: cannot import name 'StandardScalerfrom' from 'sklearn.preprocessing' (/redacted/.conda/envs/custom_fractal_task_collection/lib/python3.10/site-packages/sklearn/preprocessing/__init__.py)" |
| 206 | + ); |
| 207 | + expect(parts[2].highlight).eq(true); |
| 208 | +}); |
| 209 | + |
| 210 | +it('handles null or undefined inputs', () => { |
| 211 | + expect(extractJobErrorParts(null)).toHaveLength(0); |
| 212 | + expect(extractJobErrorParts()).toHaveLength(0); |
| 213 | + expect(extractRelevantJobError(null)).eq(''); |
| 214 | + expect(extractRelevantJobError()).eq(''); |
| 215 | +}); |
0 commit comments