Skip to content

Commit

Permalink
#9466: Handling GetFeatureInfo exceptions parameter format configurat…
Browse files Browse the repository at this point in the history
…ion (#9471) (#9802)

Co-authored-by: mahmoud adel <[email protected]>
  • Loading branch information
dsuren1 and mahmoudadel54 authored Dec 7, 2023
1 parent 5225012 commit d42870e
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 51 deletions.
40 changes: 0 additions & 40 deletions web/client/epics/__tests__/identify-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
LOAD_FEATURE_INFO,
NO_QUERYABLE_LAYERS,
ERROR_FEATURE_INFO,
EXCEPTIONS_FEATURE_INFO,
SHOW_MAPINFO_MARKER,
HIDE_MAPINFO_MARKER,
GET_VECTOR_INFO,
Expand Down Expand Up @@ -401,45 +400,6 @@ describe('identify Epics', () => {
}
}, state);
});
it('getFeatureInfoOnFeatureInfoClick handle server exception', (done) => {
// remove previous hook
registerHook('RESOLUTION_HOOK', undefined);
const state = {
map: TEST_MAP_STATE,
mapInfo: {
clickPoint: { latlng: { lat: 36.95, lng: -79.84 } }
},
layers: {
flat: [{
id: "TEST",
"title": "TITLE",
type: "wms",
visibility: true,
url: 'base/web/client/test-resources/featureInfo-exception.json'
}]
}
};
const sentActions = [featureInfoClick({ latlng: { lat: 36.95, lng: -79.84 } })];
testEpic(getFeatureInfoOnFeatureInfoClick, 3, sentActions, ([a0, a1, a2]) => {
try {
expect(a0).toExist();
expect(a0.type).toBe(PURGE_MAPINFO_RESULTS);
expect(a1).toExist();
expect(a1.type).toBe(NEW_MAPINFO_REQUEST);
expect(a1.reqId).toExist();
expect(a1.request).toExist();
expect(a2).toExist();
expect(a2.type).toBe(EXCEPTIONS_FEATURE_INFO);
expect(a2.exceptions).toExist();
expect(a2.reqId).toExist();
expect(a2.requestParams).toExist();
expect(a2.layerMetadata.title).toBe(state.layers.flat[0].title);
done();
} catch (ex) {
done(ex);
}
}, state);
});
it('Test local request, remote request and skip background layers', done => {
const LAYERS = [{
id: 'OpenTopoMap__3',
Expand Down
10 changes: 3 additions & 7 deletions web/client/epics/identify.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
PURGE_MAPINFO_RESULTS, EDIT_LAYER_FEATURES,
UPDATE_FEATURE_INFO_CLICK_POINT,
featureInfoClick, updateCenterToMarker, purgeMapInfoResults,
exceptionsFeatureInfo, loadFeatureInfo, errorFeatureInfo,
loadFeatureInfo, errorFeatureInfo,
noQueryableLayers, newMapInfoRequest, getVectorInfo,
showMapinfoMarker, hideMapinfoMarker, setCurrentEditFeatureQuery,
SET_MAP_TRIGGER, CLEAR_WARNING
Expand Down Expand Up @@ -129,12 +129,8 @@ export const getFeatureInfoOnFeatureInfoClick = (action$, { getState = () => { }
// this delay allows the panel to open and show the spinner for the first one
// this delay mitigates the freezing of the app when there are a great amount of queried layers at the same time
.delay(0)
.map((response) =>
response.data.exceptions
? exceptionsFeatureInfo(reqId, response.data.exceptions, requestParams, lMetaData)
: loadFeatureInfo(reqId, response.data, requestParams, { ...lMetaData, features: response.features, featuresCrs: response.featuresCrs }, layer)
)
.catch((e) => Rx.Observable.of(errorFeatureInfo(reqId, e.data || e.statusText || e.status, requestParams, lMetaData)))
.map((response) =>loadFeatureInfo(reqId, response.data, requestParams, { ...lMetaData, features: response.features, featuresCrs: response.featuresCrs }, layer))
.catch((e) => Rx.Observable.of(errorFeatureInfo(reqId, e, requestParams, lMetaData)))
.concat(Rx.Observable.defer(() => {
// update the layout only after the initial response
// we don't need to trigger this for each query layer
Expand Down
164 changes: 164 additions & 0 deletions web/client/utils/mapinfo/__tests__/wms-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* Copyright 2023, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import expect from 'expect';

import MockAdapter from "axios-mock-adapter";

import axios from '../../../libs/ajax';
import {INFO_FORMATS} from "../../FeatureInfoUtils";
import {getFeatureInfo} from "../../../api/identify";
import wms from '../wms';

describe('mapinfo wms utils', () => {
let mockAxios;
beforeEach((done) => {
mockAxios = new MockAdapter(axios);
setTimeout(done);
});
afterEach((done) => {
if (mockAxios) {
mockAxios.restore();
}
mockAxios = null;
setTimeout(done);
});
it('should return the response object from getIdentifyFlow in case of 200 with empty features,', (done) => {
const SAMPLE_LAYER = {
type: "wms",
name: "test_layer"
};
mockAxios.onGet().reply(() => {
return [200, {
"type": "FeatureCollection",
"features": [],
"totalFeatures": "unknown",
"numberReturned": 0,
"timeStamp": "2023-09-22T08:50:30.808Z",
"crs": null
}];
});
getFeatureInfo(
"TEST_URL", {
info_format: INFO_FORMATS.PROPERTIES
}, SAMPLE_LAYER
).subscribe(
n => {
expect(n.data.features.length).toEqual(0);
expect(n.features).toEqual([]);
done();
},
error => {
return done(error);
}
);
});
it('should return the response object from getIdentifyFlow in case of 200 with features,', (done) => {
const SAMPLE_LAYER = {
type: "wms",
name: "test_layer"
};
mockAxios.onGet().reply(() => {
return [200, {
"type": "FeatureCollection",
"features": [{}, {}],
"totalFeatures": "unknown",
"numberReturned": 2,
"timeStamp": "2023-09-22T08:50:30.808Z",
"crs": null
}];
});
getFeatureInfo(
"TEST_URL", {
info_format: INFO_FORMATS.PROPERTIES
}, SAMPLE_LAYER
).subscribe(
n => {
expect(n.data.features.length).toEqual(2);
expect(n.features.length).toEqual(2);
done();
},
error => {
return done(error);
}
);
});
it('should return the response object from getIdentifyFlow in case no data features as a text,', (done) => {
const SAMPLE_LAYER = {
type: "wms",
name: "test_layer"
};
mockAxios.onGet().reply(() => {
return [200, 'no features were found'];
});
getFeatureInfo(
"TEST_URL", {
info_format: INFO_FORMATS.TEXT
}, SAMPLE_LAYER
).subscribe(
n => {
expect(n.data).toEqual('no features were found');
done();
},
error => {
return done(error);
}
);
});
it('test intercept ogc error in wms if success', (done)=>{
mockAxios.onGet().reply(() => {
return [200, {
"type": "FeatureCollection",
"features": [],
"totalFeatures": "unknown",
"numberReturned": 0,
"timeStamp": "2023-09-22T08:50:30.808Z",
"crs": null
}];
});
wms
.getIdentifyFlow(undefined, "/", { features: [] })
.subscribe((response) => {
expect(response?.data?.features).toEqual([]);
done();
});
});
it('test intercept ogc error in wms if exception', (done)=>{
mockAxios.onGet().reply(() => {
return [200, `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE ServiceExceptionReport SYSTEM "https://geobretagne.fr/geoserver/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd">
<ServiceExceptionReport version="1.1.1" >
<ServiceException>
java.lang.NumberFormatException: For input string: &quot;asd&quot;
For input string: &quot;asd&quot;
</ServiceException>
</ServiceExceptionReport>`];
});
wms
.getIdentifyFlow(undefined, "/", { features: [] })
.subscribe((response) => {
expect(response?.data?.exceptions).toExist();
}, error=>{
expect(error.name).toEqual('OGCError');
done();
});
});
it('test intercept ogc error in wms if failed', (done)=>{
mockAxios.onGet().reply(() => {
return [404, {}];
});
wms
.getIdentifyFlow(undefined, "/", { features: [] })
.subscribe((response) => {
expect(response?.data?.features).toEqual([]);
}, error => {
expect(error.status).toEqual(404);
done();
});
});
});
19 changes: 15 additions & 4 deletions web/client/utils/mapinfo/wms.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
* LICENSE file in the root directory of this source tree.
*/

import {Observable} from "rxjs";
import {getCurrentResolution} from '../MapUtils';
import {reproject, getProjectedBBox, normalizeSRS} from '../CoordinatesUtils';
import {getLayerUrl} from '../LayersUtils';
import {isObject, isNil} from 'lodash';
import { optionsToVendorParams } from '../VendorParamsUtils';
import { generateEnvString } from '../LayerLocalizationUtils';

import axios from "../../libs/ajax";
// import {parseString} from "xml2js";
// import {stripPrefix} from "xml2js/lib/processors";
import {addAuthenticationToSLD} from '../SecurityUtils';
import assign from 'object-assign';

import { interceptOGCError } from '../ObservableUtils';
export default {
/**
* Creates the request object and it's metadata for WMS GetFeatureInfo.
Expand Down Expand Up @@ -59,7 +62,6 @@ export default {
service: 'WMS',
version: '1.1.1',
request: 'GetFeatureInfo',
exceptions: 'application/json',
id: layer.id,
layers: layer.name,
query_layers: queryLayers,
Expand All @@ -86,5 +88,14 @@ export default {
},
url: getLayerUrl(layer).replace(/[?].*$/g, '')
};
}
},
/**
* Returns an Observable that emits the response when ready.
* @param {object} layer the layer
* @param {string} baseURL the URL for the request
* @param {object} params for the request
*/
getIdentifyFlow: (layer, basePath, params) =>
Observable.defer(() => axios.get(basePath, { params }))
.let(interceptOGCError)
};

0 comments on commit d42870e

Please sign in to comment.