From 1eb66a9d0321ee28abc453a19d355d1f79d524eb Mon Sep 17 00:00:00 2001 From: Momtchil Momtchev Date: Tue, 3 Jan 2023 18:31:15 +0100 Subject: [PATCH] Propagate errors in the multiplexer (#57) * propagate errors in the multiplexer * do not fail the test when GDAL does not open the file * update the changelog * propagate errors in calcAsync * fix the codecov YAML syntax * the the progress catch --- CHANGELOG.md | 5 +++++ codecov.yml | 4 +++- lib/calc.js | 6 +++++- lib/multiplexer.js | 8 +++++++ test/api_utils.test.ts | 45 +++++++++++++++++++++++++++++++++++++++ test/data/truncated.tiff | Bin 0 -> 1024 bytes 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/data/truncated.tiff diff --git a/CHANGELOG.md b/CHANGELOG.md index 97597938b..f828e966a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.6.2] 2023-01-03 + +### Changed + - Fix [#56](https://github.com/mmomtchev/node-gdal-async/issues/56), propagate input errors in `calcAsync` and `RasterMuxStream` + ## [3.6.1] 2022-12-21 ### Added diff --git a/codecov.yml b/codecov.yml index 20c6627ec..dca05d81b 100644 --- a/codecov.yml +++ b/codecov.yml @@ -14,4 +14,6 @@ coverage: - "src" - "lib" patch: - default: 80% + default: + target: auto + threshold: 2% diff --git a/lib/calc.js b/lib/calc.js index 7d392da74..154853e85 100644 --- a/lib/calc.js +++ b/lib/calc.js @@ -113,7 +113,11 @@ const calc = (gdal) => function calcAsync(inputs, output, fn, options) { mux.on('data', (chunk) => { processed += chunk[Object.keys(chunk)[0]].length const done = processed / length - progress(done) + try { + progress(done) + } catch (e) { + reject(e) + } }) } diff --git a/lib/multiplexer.js b/lib/multiplexer.js index 8014b53ca..b59b71f47 100644 --- a/lib/multiplexer.js +++ b/lib/multiplexer.js @@ -65,6 +65,7 @@ class RasterMuxStream extends Readable { this.endHandlers = {} this.blockOptimize = (options || {}).blockOptimize this.rasterHighWaterMark = Infinity + for (const id of this.ids) { const inp = inputs[id] if (!(inp instanceof Readable)) throw new TypeError('inputs must be a map of Readables') @@ -80,6 +81,8 @@ class RasterMuxStream extends Readable { this.endHandlers[id] = this.inputEnded.bind(this, id) this.inputs[id].on('end', this.endHandlers[id]) + + this.inputs[id].on('error', this.errorHandler.bind(this)) } } @@ -194,6 +197,11 @@ class RasterMuxStream extends Readable { this.tryEnd() } + errorHandler(e) { + debug('emitting error', e) + this.destroy(e) + } + _read() { debug('readStart') this.throttle(true) diff --git a/test/api_utils.test.ts b/test/api_utils.test.ts index f68d79d16..a8dd7e64d 100644 --- a/test/api_utils.test.ts +++ b/test/api_utils.test.ts @@ -593,6 +593,51 @@ describe('gdal_utils', () => { ) }) + it('should reject when the file is corrupted', function () { + const tempFile = `/vsimem/invalid_calc_${String(Math.random()).substring(2)}.tiff` + let T2m, D2m + try { + T2m = gdal.open(path.resolve(__dirname, 'data','AROME_T2m_10.tiff')) + D2m = gdal.open(path.resolve(__dirname, 'data','truncated.tiff')) + } catch (e) { + // Older GDAL versions cannot open the truncated file, so this is + // considered a successful test too + this.skip() + } + const size = T2m.rasterSize + const espyFn = (t: number, td: number) => 125 * (t - td) + return assert.isRejected( + gdal.calcAsync({ + A: T2m.bands.get(1), + B: D2m.bands.get(1) + }, + gdal.open(tempFile, 'w', 'GTiff', size.x, size.y, 1, gdal.GDT_Float64).bands.get(1), + espyFn), + /Cannot read/ + ) + }) + + it('should reject on progress exception', () => { + const tempFile = `/vsimem/invalid_calc_${String(Math.random()).substring(2)}.tiff` + const T2m = gdal.open(path.resolve(__dirname, 'data','AROME_T2m_10.tiff')) + const D2m = gdal.open(path.resolve(__dirname, 'data','AROME_D2m_10.tiff')) + const size = T2m.rasterSize + const espyFn = (t: number, td: number) => 125 * (t - td) + return assert.isRejected( + gdal.calcAsync({ + A: T2m.bands.get(1), + B: D2m.bands.get(1) + }, + gdal.open(tempFile, 'w', 'GTiff', size.x, size.y, 1, gdal.GDT_Float64).bands.get(1), + espyFn, + { progress_cb: () => { + throw new Error('progress error') + } } + ), + /progress error/ + ) + }) + it('should reject when raster sizes do not match', () => { const tempFile = `/vsimem/invalid_calc_${String(Math.random()).substring(2)}.tiff` const espyFn = (t: number, td: number) => 125 * (t - td) diff --git a/test/data/truncated.tiff b/test/data/truncated.tiff new file mode 100644 index 0000000000000000000000000000000000000000..7ef64eb90d8bc94c8907ff1f65a61e6217dcc99d GIT binary patch literal 1024 zcmYk*OGs5w6b9h!y=rQfT2xk2IFKOJfr11*2S$leLPbP@4TMNC(+aW&nh8o1p;?hR z2_llTq6bn0Nm)iT& z<|C)sz#v!Ypo(g?>V0cZtD}AMi=FnFl^wzh;}wq4OFw1m-&vgFTcA;`n&Z52-$$9T z#xQ@Z+f5ULTqk-?C2XdiBg}HvydH{3VILJtIk$)RjM1TXm~@&QU!sz26ylQ!1N?Ab zYm9kB=l0TI&Iq$SwBLiY$gR{8y}y%0{iXagw}A6x^Vph=l#xpnaV9;-E~4jJ;CK_M z?B)WqMDOJZ5BN-t^*ZUHhz7M{(um&U0556d6%$17a+K(LGvw(F{QCwR-}2w6r;Bl} O(aSUwEZ1{~zKp+mKYwok literal 0 HcmV?d00001