Skip to content

Commit

Permalink
resolve review comments
Browse files Browse the repository at this point in the history
description: write unit test for add recordsfor 3d tile layers
  • Loading branch information
mahmoudadel54 committed Oct 23, 2023
1 parent 446ad51 commit 1902e96
Show file tree
Hide file tree
Showing 4 changed files with 1,549 additions and 38 deletions.
90 changes: 53 additions & 37 deletions web/client/api/CSW.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import { THREE_D_TILES, getCapabilities } from './ThreeDTiles';

const parseUrl = (url) => {
const parsed = urlUtil.parse(url, true);
return urlUtil.format(assign({}, parsed, {search: null}, {
return urlUtil.format(assign({}, parsed, { search: null }, {
query: assign({
service: "CSW",
version: "2.0.2"
}, parsed.query, {request: undefined})
}, parsed.query, { request: undefined })
}));
};

Expand Down Expand Up @@ -74,13 +74,13 @@ export const cswGetRecordsXml = '<csw:GetRecords xmlns:csw="http://www.opengis.n
* @param {object} filter.dynamicFilter filter when search text is present and is applied in conjunction with static filter
* @return {string} constructed xml string
*/
export const constructXMLBody = (startPosition, maxRecords, searchText, {filter} = {}) => {
export const constructXMLBody = (startPosition, maxRecords, searchText, { filter } = {}) => {
const staticFilter = filter?.staticFilter || defaultStaticFilter;
const dynamicFilter = `<ogc:And>
${template(filter?.dynamicFilter || defaultDynamicFilter)({searchText})}
${template(filter?.dynamicFilter || defaultDynamicFilter)({ searchText })}
${staticFilter}
</ogc:And>`;
return template(cswGetRecordsXml)({filterXml: !searchText ? staticFilter : dynamicFilter, startPosition, maxRecords});
return template(cswGetRecordsXml)({ filterXml: !searchText ? staticFilter : dynamicFilter, startPosition, maxRecords });
};

// Extract the relevant information from the wms URL for (RNDT / INSPIRE)
Expand All @@ -93,7 +93,7 @@ const extractWMSParamsFromURL = wms => {
...wms,
protocol: 'OGC:WMS',
name: layerName,
value: `${wms.value.match( /[^\?]+[\?]+/g)}SERVICE=WMS${wmsVersion && `&VERSION=${wmsVersion}`}`
value: `${wms.value.match(/[^\?]+[\?]+/g)}SERVICE=WMS${wmsVersion && `&VERSION=${wmsVersion}`}`
};
}
return false;
Expand Down Expand Up @@ -138,7 +138,7 @@ export const getLayerReferenceFromDc = (dc, options, checkEsri = true) => {
const URI = dc?.URI && castArray(dc.URI);
// look in URI objects for wms and thumbnail
if (URI) {
const wms = head(URI.map( uri => {
const wms = head(URI.map(uri => {
if (uri.protocol) {
if (REGEX_WMS_EXPLICIT.some(regex => uri.protocol.match(regex))) {
/** wms protocol params are explicitly defined as attributes (INSPIRE)*/
Expand Down Expand Up @@ -170,7 +170,7 @@ export const getLayerReferenceFromDc = (dc, options, checkEsri = true) => {
return ref.scheme && ref.scheme === "WWW:DOWNLOAD-REST_MAP";
}));
if (esri) {
return toReference('arcgis', {...esri, name: dc.alternative}, options);
return toReference('arcgis', { ...esri, name: dc.alternative }, options);
}
}
}
Expand Down Expand Up @@ -198,41 +198,67 @@ const addCapabilitiesToRecords = (_dcRef, result, options) => {
return result;
}
const { value: _url } = _dcRef?.find(t =>
REGEX_WMS_ALL.some(regex=> t?.scheme?.match(regex) || t?.protocol?.match(regex))) || {}; // Get WMS URL from references
REGEX_WMS_ALL.some(regex => t?.scheme?.match(regex) || t?.protocol?.match(regex))) || {}; // Get WMS URL from references
const [parsedUrl] = _url && _url.split('?') || [];
if (!parsedUrl) return {...result}; // Return record when no url found
if (!parsedUrl) return { ...result }; // Return record when no url found

const cached = capabilitiesCache[parsedUrl];
const isCached = !isEmpty(cached);
return Promise.resolve(
isCached
? cached
: WMS.getCapabilities(parsedUrl + '?version=')
.then((caps)=> WMS.flatLayers(caps.Capability))
.catch(()=> []))
.then((caps) => WMS.flatLayers(caps.Capability))
.catch(() => []))
.then((layers) => {
if (!isCached) {
capabilitiesCache[parsedUrl] = layers;
}
// Add visibility limits scale data of the layer to the record
return {
...result,
records: result?.records?.map(record=> {
records: result?.records?.map(record => {
const name = get(getLayerReferenceFromDc(record?.dc, null, false), 'params.name', '');
const {
MinScaleDenominator,
MaxScaleDenominator
} = layers.find(l=> l.Name === name) || {};
} = layers.find(l => l.Name === name) || {};
return {
...record,
...((!isNil(MinScaleDenominator) || !isNil(MaxScaleDenominator))
&& {capabilities: {MaxScaleDenominator, MinScaleDenominator}})
&& { capabilities: { MaxScaleDenominator, MinScaleDenominator } })
};
})
};
});
};

/**
* handle getting bbox from capabilities in case of 3D tile layer for CSW records
* @param {object} result csw results object
* @return {object} csw records
*/
const getBboxFor3DLayersToRecords = async(result)=> {
if (!result) return result;
let { records } = result;
if (records?.length) {
let records3D = records.filter(rec=>rec?.dc?.format === THREE_D_TILES);
let records3DPromisesForCapabilities = records3D.map(rec=>{
let tilesetJsonURL = rec.dc?.URI?.value;
return getCapabilities(tilesetJsonURL);
});
if (!records3DPromisesForCapabilities.length) return result;
let res = await Promise.all(records3DPromisesForCapabilities);
res.forEach((recCapabilities, idx)=>{
let bbox = getExtentFromNormalized(recCapabilities.bbox.bounds, recCapabilities.bbox.crs);
records3D[idx].boundingBox = {
extent: bbox.extent,
crs: recCapabilities.bbox.crs
};
});
return result;
}
return result;
};
/**
* API for local config
*/
Expand All @@ -244,7 +270,7 @@ const Api = {
resolve(axios.get(catalogURL)
.then((response) => {
if (response) {
const {unmarshaller} = require('../utils/ogc/CSW');
const { unmarshaller } = require('../utils/ogc/CSW');
const json = unmarshaller.unmarshalString(response.data);
if (json && json.name && json.name.localPart === "GetRecordByIdResponse" && json.value && json.value.abstractRecord) {
let dcElement = json.value.abstractRecord[0].value.dcElement;
Expand Down Expand Up @@ -277,7 +303,7 @@ const Api = {
dc[elName] = finalEl;
}
}
return {dc};
return { dc };
}
} else if (json && json.name && json.name.localPart === "ExceptionReport") {
return {
Expand All @@ -294,17 +320,19 @@ const Api = {
getRecords: function(url, startPosition, maxRecords, filter, options) {
return new Promise((resolve) => {
require.ensure(['../utils/ogc/CSW', '../utils/ogc/Filter'], () => {
const {CSW, marshaller, unmarshaller } = require('../utils/ogc/CSW');
const { CSW, marshaller, unmarshaller } = require('../utils/ogc/CSW');
let body = marshaller.marshalString({
name: "csw:GetRecords",
value: CSW.getRecords(startPosition, maxRecords, typeof filter !== "string" && filter)
});
if (!filter || typeof filter === "string") {
body = constructXMLBody(startPosition, maxRecords, filter, options);
}
resolve(axios.post(parseUrl(url), body, { headers: {
'Content-Type': 'application/xml'
}}).then(async(response) => {
resolve(axios.post(parseUrl(url), body, {
headers: {
'Content-Type': 'application/xml'
}
}).then((response) => {
if (response) {
let json = unmarshaller.unmarshalString(response.data);
if (json && json.name && json.name.localPart === "GetRecordsResponse" && json.value && json.value.searchResults) {
Expand Down Expand Up @@ -409,18 +437,6 @@ const Api = {
}
obj.dc = dc;
}
// if it is 3D layer ---> get layer extent from tilesetJson
if (obj?.dc?.format === THREE_D_TILES) {
let tilesetJsonURL = obj.dc?.URI?.value;
if (tilesetJsonURL) {
let data = await getCapabilities(tilesetJsonURL);
let bbox = getExtentFromNormalized(data.bbox.bounds, data.bbox.crs);
obj.boundingBox = {
extent: bbox.extent,
crs: data.bbox.crs
};
}
}
records.push(obj);
}
}
Expand All @@ -433,7 +449,7 @@ const Api = {
}
}
return null;
}));
}).then(results=>getBboxFor3DLayersToRecords(results))); // handle getting bbox from capabilities in case of 3D tile layer
});
});
},
Expand All @@ -445,7 +461,7 @@ const Api = {
workspaceSearch: function(url, startPosition, maxRecords, text, workspace) {
return new Promise((resolve) => {
require.ensure(['../utils/ogc/CSW', '../utils/ogc/Filter'], () => {
const {Filter} = require('../utils/ogc/Filter');
const { Filter } = require('../utils/ogc/Filter');
const workspaceTerm = workspace || "%";
const layerNameTerm = text && "%" + text + "%" || "%";
const ops = Filter.propertyIsLike("dc:identifier", workspaceTerm + ":" + layerNameTerm);
Expand All @@ -454,7 +470,7 @@ const Api = {
});
});
},
reset: () => {}
reset: () => { }
};

export default Api;
111 changes: 110 additions & 1 deletion web/client/api/__tests__/CSW-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import expect from 'expect';
import axios from '../../libs/ajax';
import MockAdapter from 'axios-mock-adapter';
import GRDCResponse from 'raw-loader!../../test-resources/csw/getRecordsResponseDC.xml';
import GRDCResponseWith3DLayers from 'raw-loader!../../test-resources/csw/getRecordsResponseDCWith3DLayers.xml';
import API, {constructXMLBody, getLayerReferenceFromDc } from '../CSW';

import API, {constructXMLBody, getLayerReferenceFromDc} from '../CSW';
import tileSetResponse from '../../test-resources/3dtiles/tileSetSample2.json';

describe('Test correctness of the CSW APIs', () => {
it('getRecords ISO Metadata Profile', (done) => {
Expand Down Expand Up @@ -281,4 +283,111 @@ describe("getLayerReferenceFromDc", () => {
expect(layerRef.type).toBe('arcgis');
expect(layerRef.url).toBe('http://esri_url');
});

});

describe("getLayerReferenceFromDc", () => {
const threeDLayerRecord = {
"boundingBox": {
"extent": [
11.244154369601063,
43.75907090685874,
11.265929832205956,
43.78084636946362
],
"crs": "EPSG:4326"
},
"dc": {
"references": [],
"identifier": "test:20230829_test_3dtile_01",
"date": "2023-09-22",
"title": "Metadato di test per 3D-tile",
"abstract": "Breve descrizione della risorsa",
"description": "Breve descrizione della risorsa",
"type": "dataset",
"subject": [
"Zone a rischio naturale",
"health"
],
"format": "3D Tiles",
"contributor": "Nome dell'ufficio responsabile del dato",
"rights": [
"otherRestrictions",
"otherRestrictions"
],
"language": "ita",
"source": "Descrizione della provenienza e del processo di produzione del dato (storia, ciclo di vita, rilevazione, acquisizione, forma attuale, qualità richiesta per garantirne l'interoperabilità)",
"temporal": "start=2009-01-01; end=2013-12-31",
"URI": {
"TYPE_NAME": "DC_1_1.URI",
"protocol": "https://registry.geodati.gov.it/metadata-codelist/ProtocolValue/www-download",
"description": "access point",
"value": "https://3d-layers.s3.eu-central-1.amazonaws.com/3dtiles/centro_storico_di_firenze_-_brass_city_model/tileset.json"
}
}
};
let mockAxios;
beforeEach((done) => {
mockAxios = new MockAdapter(axios);
setTimeout(done);
});
afterEach((done) => {
mockAxios.restore();
setTimeout(done);
});
it('test getBboxFor3DLayersToRecords function that handles getting bbox for 3D tile layers from ', (done) => {
mockAxios.onPost().replyOnce(()=>{
return [200, GRDCResponseWith3DLayers];
});
mockAxios.onGet().reply(()=>{
return [200, tileSetResponse];
});
mockAxios.onGet().reply(()=>{
return [200, tileSetResponse];
});
API.getRecords('base/web/client/test-resources/csw/getRecordsResponseDCWith3DLayers.xml', 1, 2).then((result) => {
try {
expect(result).toExist();
expect(result.records).toExist();
expect(result.records.length).toBe(5);
const [rec0, rec1, rec2, rec3, rec4] = result.records;

expect(rec0.dc).toExist();
expect(rec0.boundingBox).toExist();
expect(rec0.boundingBox.crs).toBe('EPSG:4326');
expect(rec0.boundingBox.extent).toEqual([45.542, 11.874, 46.026, 12.718]);
expect(rec1.dc.format).toEqual("3D Tiles");
expect(rec1.boundingBox).toExist();
expect(rec1.boundingBox.crs).toBe('EPSG:4326');
expect(rec1.boundingBox.extent[0]).toEqual(threeDLayerRecord.boundingBox.extent[0]);
expect(rec1.boundingBox.extent[1]).toEqual(threeDLayerRecord.boundingBox.extent[1]);
expect(rec1.boundingBox.extent[2]).toEqual(threeDLayerRecord.boundingBox.extent[2]);
expect(rec1.boundingBox.extent[3]).toEqual(threeDLayerRecord.boundingBox.extent[3]);
expect(rec2.dc.URI).toExist();
expect(rec2.dc.URI[0]).toExist();
const uri = rec2.dc.URI[0];
expect(uri.name).toExist();
expect(uri.value).toExist();
expect(uri.description).toExist();
expect(rec2.boundingBox).toExist();
expect(rec2.boundingBox.crs).toBe('EPSG:4326');
expect(rec2.boundingBox.extent).toEqual([ 12.002717999999996, 45.760718, 12.429282000000002, 46.187282]);
expect(rec3.boundingBox).toExist();
expect(rec3.boundingBox.crs).toBe('EPSG:4326');
expect(rec3.boundingBox.extent).toEqual([ -4.14168, 47.93257, -4.1149, 47.959353362144 ]);
expect(rec4.dc.format).toEqual("3D Tiles");
expect(rec4.boundingBox).toExist();
expect(rec4.boundingBox.crs).toBe('EPSG:4326');
expect(rec4.boundingBox.extent[0]).toEqual(threeDLayerRecord.boundingBox.extent[0]);
expect(rec4.boundingBox.extent[1]).toEqual(threeDLayerRecord.boundingBox.extent[1]);
expect(rec4.boundingBox.extent[2]).toEqual(threeDLayerRecord.boundingBox.extent[2]);
expect(rec4.boundingBox.extent[3]).toEqual(threeDLayerRecord.boundingBox.extent[3]);
done();
} catch (ex) {
done(ex);
}
});
done();

});
});
Loading

0 comments on commit 1902e96

Please sign in to comment.