diff --git a/openeo.d.ts b/openeo.d.ts index 95f74e3..e340e47 100644 --- a/openeo.d.ts +++ b/openeo.d.ts @@ -97,9 +97,9 @@ declare module OpenEO { * Creates an instance of this object. * * @param {Connection} connection - A Connection object representing an established connection to an openEO back-end. - * @param {Array} properties - A mapping from the API property names to the JS client property names (usually to convert between snake_case and camelCase), e.g. `["id", "title", ["process_graph", "processGraph"]]` + * @param {Array.>} properties - A mapping from the API property names to the JS client property names (usually to convert between snake_case and camelCase), e.g. `["id", "title", ["process_graph", "processGraph"]]` */ - constructor(connection: Connection, properties?: any[]); + constructor(connection: Connection, properties?: Array>); /** * @protected * @type {Connection} @@ -312,17 +312,32 @@ declare module OpenEO { * @type {object.} */ private data; + /** + * @private + * @ignore + * @type {object.} + */ + private featureMap; /** * @private * @type {Array.} */ private features; /** - * @private - * @ignore - * @type {object.} + * Validates the capabilities. + * + * Throws an error in case of an issue, otherwise just passes. + * + * @protected + * @throws {Error} */ - private featureMap; + protected validate(): void; + /** + * Initializes the class. + * + * @protected + */ + protected init(): void; /** * Returns the capabilities response as a JSON serializable representation of the data that is API compliant. * @@ -390,6 +405,14 @@ declare module OpenEO { * @returns {Array.} Billing plans */ listPlans(): Array; + /** + * Migrates a response, if required. + * + * @param {AxiosResponse} response + * @protected + * @returns {AxiosResponse} + */ + protected migrate(response: AxiosResponse): AxiosResponse; } /** * The Authentication Provider for OpenID Connect. @@ -1504,11 +1527,11 @@ declare module OpenEO { /** * Converts a sorted array of arguments to an object with the respective parameter names. * - * @param {Array} processArgs + * @param {Array.>} processArgs * @returns {object.} * @throws {Error} */ - namedArguments(processArgs: any[]): object; + namedArguments(processArgs: Array>): object; /** * Checks the arguments given for parameters and add them to the process. * @@ -1738,10 +1761,10 @@ declare module OpenEO { /** * Gets the callback parameter specifics from the parent process. * - * @returns {Array} + * @returns {Array.>} * @todo Should this also pass callback parameters from parents until root is reached? */ - getParentCallbackParameters(): any[]; + getParentCallbackParameters(): Array>; /** * Adds a parameter to the list of process parameters. * @@ -1880,11 +1903,12 @@ declare module OpenEO { * @async * @protected * @returns {Promise} Capabilities + * @throws {Error} */ protected init(): Promise; /** * Refresh the cache for processes. - * + * * @async * @protected * @returns {Promise} @@ -1968,7 +1992,7 @@ declare module OpenEO { * 2. Lower left corner, coordinate axis 2 * 3. Upper right corner, coordinate axis 1 * 4. Upper right corner, coordinate axis 2 - * @param {?Array.<*>} [temporalExtent=null] - Limits the items to the specified temporal interval. + * @param {?Array} [temporalExtent=null] - Limits the items to the specified temporal interval. * The interval has to be specified as an array with exactly two elements (start, end) and * each must be either an RFC 3339 compatible string or a Date object. * Also supports open intervals by setting one of the boundaries to `null`, but never both. @@ -2346,21 +2370,28 @@ declare module OpenEO { * Adds links and federation:missing. * * @protected - * @param {Array} arr + * @param {Array.<*>} arr * @param {object.} response * @returns {ResponseArray} */ - protected _toResponseArray(arr: any[], response: object): any; + protected _toResponseArray(arr: Array, response: object): any; /** * Get the a link with the given rel type. * - * @protected * @param {Array.} links - An array of links. - * @param {string} rel - Relation type to find, defaults to `next`. + * @param {string|Array.} rel - Relation type(s) to find. * @returns {string | null} * @throws {Error} */ - protected _getLinkHref(links: Array, rel?: string): string | null; + getHrefForRel(links: Array, rel: string | Array): string | null; + /** + * Makes all links in the list absolute. + * + * @param {Array.} links - An array of links. + * @param {?string|AxiosResponse} [base=null] - The base url to use for relative links. + * @returns {Array.} + */ + makeLinksAbsolute(links: Array, base?: string | AxiosResponse) : Array.; /** * Sends a GET request. * diff --git a/src/capabilities.js b/src/capabilities.js index 478bac1..a06fcc0 100644 --- a/src/capabilities.js +++ b/src/capabilities.js @@ -1,5 +1,61 @@ const Utils = require('@openeo/js-commons/src/utils'); +const FEATURE_MAP = { + // Discovery + capabilities: true, + listFileTypes: 'get /file_formats', + listServiceTypes: 'get /service_types', + listUdfRuntimes: 'get /udf_runtimes', + // Collections + listCollections: 'get /collections', + describeCollection: 'get /collections/{collection_id}', + listCollectionItems: 'get /collections/{collection_id}/items', + // Processes + listProcesses: 'get /processes', + describeProcess: 'get /processes', + // Auth / Account + listAuthProviders: true, + authenticateOIDC: 'get /credentials/oidc', + authenticateBasic: 'get /credentials/basic', + describeAccount: 'get /me', + // Files + listFiles: 'get /files', + getFile: 'get /files', // getFile is a virtual function and doesn't request an endpoint, but get /files should be available nevertheless. + uploadFile: 'put /files/{path}', + downloadFile: 'get /files/{path}', + deleteFile: 'delete /files/{path}', + // User-Defined Processes + validateProcess: 'post /validation', + listUserProcesses: 'get /process_graphs', + describeUserProcess: 'get /process_graphs/{process_graph_id}', + getUserProcess: 'get /process_graphs/{process_graph_id}', + setUserProcess: 'put /process_graphs/{process_graph_id}', + replaceUserProcess: 'put /process_graphs/{process_graph_id}', + deleteUserProcess: 'delete /process_graphs/{process_graph_id}', + // Processing + computeResult: 'post /result', + listJobs: 'get /jobs', + createJob: 'post /jobs', + listServices: 'get /services', + createService: 'post /services', + getJob: 'get /jobs/{job_id}', + describeJob: 'get /jobs/{job_id}', + updateJob: 'patch /jobs/{job_id}', + deleteJob: 'delete /jobs/{job_id}', + estimateJob: 'get /jobs/{job_id}/estimate', + debugJob: 'get /jobs/{job_id}/logs', + startJob: 'post /jobs/{job_id}/results', + stopJob: 'delete /jobs/{job_id}/results', + listResults: 'get /jobs/{job_id}/results', + downloadResults: 'get /jobs/{job_id}/results', + // Web services + describeService: 'get /services/{service_id}', + getService: 'get /services/{service_id}', + updateService: 'patch /services/{service_id}', + deleteService: 'delete /services/{service_id}', + debugService: 'get /services/{service_id}/logs', +}; + /** * Capabilities of a back-end. */ @@ -12,15 +68,6 @@ class Capabilities { * @throws {Error} */ constructor(data) { - if(!Utils.isObject(data)) { - throw new Error("No capabilities retrieved."); - } - if(!data.api_version) { - throw new Error("Invalid capabilities: No API version retrieved"); - } - if(!Array.isArray(data.endpoints)) { - throw new Error("Invalid capabilities: No endpoints retrieved"); - } /** * @private @@ -28,75 +75,53 @@ class Capabilities { */ this.data = data; + /** + * @private + * @ignore + * @type {object.} + */ + this.featureMap = FEATURE_MAP; + /** * @private * @type {Array.} */ + this.features = []; + + this.validate(); + this.init(); + } + + /** + * Validates the capabilities. + * + * Throws an error in case of an issue, otherwise just passes. + * + * @protected + * @throws {Error} + */ + validate() { + if(!Utils.isObject(this.data)) { + throw new Error("No capabilities retrieved."); + } + else if(!this.data.api_version) { + throw new Error("Invalid capabilities: No API version retrieved"); + } + else if(!Array.isArray(this.data.endpoints)) { + throw new Error("Invalid capabilities: No endpoints retrieved"); + } + } + + /** + * Initializes the class. + * + * @protected + */ + init() { this.features = this.data.endpoints // Flatten features to be compatible with the feature map. .map(e => e.methods.map(method => (method + ' ' + e.path).toLowerCase())) .reduce((flat, next) => flat.concat(next), []); // .flat(1) once browser support for ECMAscript 10/2019 gets better - - /** - * @private - * @ignore - * @type {object.} - */ - this.featureMap = { - // Discovery - capabilities: true, - listFileTypes: 'get /file_formats', - listServiceTypes: 'get /service_types', - listUdfRuntimes: 'get /udf_runtimes', - // Collections - listCollections: 'get /collections', - describeCollection: 'get /collections/{collection_id}', - listCollectionItems: 'get /collections/{collection_id}/items', - // Processes - listProcesses: 'get /processes', - describeProcess: 'get /processes', - // Auth / Account - listAuthProviders: true, - authenticateOIDC: 'get /credentials/oidc', - authenticateBasic: 'get /credentials/basic', - describeAccount: 'get /me', - // Files - listFiles: 'get /files', - getFile: 'get /files', // getFile is a virtual function and doesn't request an endpoint, but get /files should be available nevertheless. - uploadFile: 'put /files/{path}', - downloadFile: 'get /files/{path}', - deleteFile: 'delete /files/{path}', - // User-Defined Processes - validateProcess: 'post /validation', - listUserProcesses: 'get /process_graphs', - describeUserProcess: 'get /process_graphs/{process_graph_id}', - getUserProcess: 'get /process_graphs/{process_graph_id}', - setUserProcess: 'put /process_graphs/{process_graph_id}', - replaceUserProcess: 'put /process_graphs/{process_graph_id}', - deleteUserProcess: 'delete /process_graphs/{process_graph_id}', - // Processing - computeResult: 'post /result', - listJobs: 'get /jobs', - createJob: 'post /jobs', - listServices: 'get /services', - createService: 'post /services', - getJob: 'get /jobs/{job_id}', - describeJob: 'get /jobs/{job_id}', - updateJob: 'patch /jobs/{job_id}', - deleteJob: 'delete /jobs/{job_id}', - estimateJob: 'get /jobs/{job_id}/estimate', - debugJob: 'get /jobs/{job_id}/logs', - startJob: 'post /jobs/{job_id}/results', - stopJob: 'delete /jobs/{job_id}/results', - listResults: 'get /jobs/{job_id}/results', - downloadResults: 'get /jobs/{job_id}/results', - // Web services - describeService: 'get /services/{service_id}', - getService: 'get /services/{service_id}', - updateService: 'patch /services/{service_id}', - deleteService: 'delete /services/{service_id}', - debugService: 'get /services/{service_id}/logs', - }; } /** @@ -215,6 +240,17 @@ class Capabilities { return []; } } + + /** + * Migrates a response, if required. + * + * @param {AxiosResponse} response + * @protected + * @returns {AxiosResponse} + */ + migrate(response) { // eslint-disable-line no-unused-vars + return response; + } } module.exports = Capabilities; diff --git a/src/connection.js b/src/connection.js index 4e889f4..92b877e 100644 --- a/src/connection.js +++ b/src/connection.js @@ -18,6 +18,11 @@ const Service = require('./service'); const Builder = require('./builder/builder'); const BuilderNode = require('./builder/node'); +const CONFORMANCE_RELS = [ + 'conformance', + 'http://www.opengis.net/def/rel/ogc/1.0/conformance' +]; + /** * A connection to a back-end. */ @@ -98,10 +103,24 @@ class Connection { * @async * @protected * @returns {Promise} Capabilities + * @throws {Error} */ async init() { let response = await this._get('/'); - this.capabilitiesObject = new Capabilities(response.data); + let data = Object.assign({}, response.data); + data.links = this.makeLinksAbsolute(data.links, response); + + if (!Array.isArray(data.conformsTo) && Array.isArray(data.links)) { + let conformanceLink = this._getLinkHref(data.links, CONFORMANCE_RELS); + if (conformanceLink) { + let response2 = await this._get(conformanceLink); + if (Utils.isObject(response2.data) && Array.isArray(response2.data.conformsTo)) { + data.conformsTo = response2.data.conformsTo; + } + } + } + + this.capabilitiesObject = new Capabilities(data); return this.capabilitiesObject; } @@ -210,7 +229,12 @@ class Connection { async listCollections() { let response = await this._get('/collections'); if (Utils.isObject(response.data) && Array.isArray(response.data.collections)) { - response.data.collections = response.data.collections.map(collection => StacMigrate.collection(collection)); + response.data.collections = response.data.collections.map(collection => { + if (collection.stac_version) { + return StacMigrate.collection(collection); + } + return collection; + }); } return response.data; } @@ -227,7 +251,12 @@ class Connection { */ async describeCollection(collectionId) { let response = await this._get('/collections/' + collectionId); - return StacMigrate.collection(response.data); + if (response.data.stac_version) { + return StacMigrate.collection(response.data); + } + else { + return response.data; + } } /** @@ -282,12 +311,18 @@ class Connection { let response = await this._get(nextUrl, params); if (Utils.isObject(response.data) && Array.isArray(response.data.features)) { - response.data.features = response.data.features.map(item => StacMigrate.item(item)); + response.data.features = response.data.features.map(item => { + if (item.stac_version) { + return StacMigrate.item(item); + } + return item; + }); } yield response.data; page++; - nextUrl = this._getLinkHref(response.data.links); + let links = this.makeLinksAbsolute(response.data.links); + nextUrl = this._getLinkHref(links, 'next'); } } @@ -1007,20 +1042,60 @@ class Connection { * * @protected * @param {Array.} links - An array of links. - * @param {string} rel - Relation type to find, defaults to `next`. + * @param {string|Array.} rel - Relation type(s) to find. * @returns {string | null} * @throws {Error} */ - _getLinkHref(links, rel = 'next') { + _getLinkHref(links, rel) { + if (!Array.isArray(rel)) { + rel = [rel]; + } if (Array.isArray(links)) { - let nextLink = links.find(link => Utils.isObject(link) && link.rel === rel && typeof link.href === 'string'); - if (nextLink) { - return nextLink.href; + let link = links.find(l => Utils.isObject(l) && rel.includes(l.rel) && typeof l.href === 'string'); + if (link) { + return link.href; } } return null; } + /** + * Makes all links in the list absolute. + * + * @param {Array.} links - An array of links. + * @param {?string|AxiosResponse} [base=null] - The base url to use for relative links, or an response to derive the url from. + * @returns {Array.} + */ + makeLinksAbsolute(links, base = null) { + if (!Array.isArray(links)) { + return links; + } + let baseUrl = null; + if (base.headers && base.config && base.request) { // AxiosResponse + baseUrl = base.config.baseURL + base.config.url; + } + else if (typeof base !== 'string') { + baseUrl = this._getLinkHref(links, 'self'); + } + else { + baseUrl = base; + } + if (!baseUrl) { + return links; + } + return links.map((link) => { + if (!Utils.isObject(link) || typeof link.href !== 'string') { + return link; + } + try { + let url = new URL(link.href, baseUrl); + return Object.assign({}, link, {href: url.toString()}); + } catch(error) { + return link; + } + }); + } + /** * Sends a GET request. * @@ -1176,7 +1251,12 @@ class Connection { } try { - return await axios(options); + let response = await axios(options); + let capabilities = this.capabilities(); + if (capabilities) { + response = capabilities.migrate(response); + } + return response; } catch(error) { const checkContentType = type => (typeof type === 'string' && type.indexOf('/json') !== -1); const enrichError = (origin, response) => { diff --git a/tests/earthengine.test.js b/tests/earthengine.test.js index b406515..406f5f3 100644 --- a/tests/earthengine.test.js +++ b/tests/earthengine.test.js @@ -17,9 +17,9 @@ describe('GEE back-end', () => { const FREE_PLAN = {"name":"free","description":"Earth Engine is free for research, education, and nonprofit use. For commercial applications, Google offers paid commercial licenses. Please contact earthengine-commercial@google.com for details.","paid":false}; - const TESTCAPABILITIES = {"api_version":"1.0.1","backend_version":"1.0.0-beta.5","stac_version":"1.0.0","type":"Catalog","production":false,"id":"openeo-earthengine-driver","title":"Google Earth Engine Proxy for openEO","description":"This is the Google Earth Engine Driver for openEO.\n\nGoogle Earth Engine is a planetary-scale platform for Earth science data & analysis. It is powered by Google's cloud infrastructure and combines a multi-petabyte catalog of satellite imagery and geospatial datasets with planetary-scale analysis capabilities. Google makes it available for scientists, researchers, and developers to detect changes, map trends, and quantify differences on the Earth's surface. Google Earth Engine is free for research, education, and nonprofit use.","endpoints":[{"path":"/","methods":["GET"]},{"path":"/conformance","methods":["GET"]},{"path":"/service_types","methods":["GET"]},{"path":"/file_formats","methods":["GET"]},{"path":"/collections","methods":["GET"]},{"path":"/collections/{collection_id}","methods":["GET"]},{"path":"/processes","methods":["GET"]},{"path":"/files","methods":["GET"]},{"path":"/files/{path}","methods":["GET","PUT","DELETE"]},{"path":"/result","methods":["POST"]},{"path":"/jobs","methods":["POST","GET"]},{"path":"/jobs/{job_id}","methods":["GET","PATCH","DELETE"]},{"path":"/jobs/{job_id}/logs","methods":["GET"]},{"path":"/jobs/{job_id}/results","methods":["GET","POST"]},{"path":"/services","methods":["GET","POST"]},{"path":"/services/{service_id}","methods":["GET","PATCH","DELETE"]},{"path":"/services/{service_id}/logs","methods":["GET"]},{"path":"/credentials/basic","methods":["GET"]},{"path":"/me","methods":["GET"]},{"path":"/validation","methods":["POST"]},{"path":"/process_graphs","methods":["GET"]},{"path":"/process_graphs/{process_graph_id}","methods":["GET","PUT","DELETE"]}],"billing":{"currency":"USD","default_plan":"free","plans":[FREE_PLAN]},"links":[{"rel":"about","href":"https://earthengine.google.com/","title":"Google Earth Engine Homepage"},{"rel":"terms-of-service","href":"https://earthengine.google.com/terms/","type":"text/html","title":"Google Earth Engine Terms of Service"},{"rel":"privacy-policy","href":"https://policies.google.com/privacy","type":"text/html","title":"Google Privacy Policy"},{"rel":"related","href":"https://github.com/Open-EO/openeo-earthengine-driver","title":"GitHub repository"},{"rel":"version-history","href":TESTBACKEND+"/.well-known/openeo","type":"application/json","title":"Supported API versions"},{"rel":"data","href":TESTBACKENDDIRECT+"/collections","type":"application/json","title":"Datasets"},{"rel":"conformance","href":TESTBACKENDDIRECT+"/conformance","type":"application/json","title":"OGC Conformance classes"}]}; + const TESTCAPABILITIES = {"api_version":"1.0.1","backend_version":"1.0.0-beta.5","stac_version":"1.0.0","type":"Catalog","production":false,"id":"openeo-earthengine-driver","title":"Google Earth Engine Proxy for openEO","conformsTo":["http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core"],"description":"This is the Google Earth Engine Driver for openEO.\n\nGoogle Earth Engine is a planetary-scale platform for Earth science data & analysis. It is powered by Google's cloud infrastructure and combines a multi-petabyte catalog of satellite imagery and geospatial datasets with planetary-scale analysis capabilities. Google makes it available for scientists, researchers, and developers to detect changes, map trends, and quantify differences on the Earth's surface. Google Earth Engine is free for research, education, and nonprofit use.","endpoints":[{"path":"/","methods":["GET"]},{"path":"/conformance","methods":["GET"]},{"path":"/service_types","methods":["GET"]},{"path":"/file_formats","methods":["GET"]},{"path":"/collections","methods":["GET"]},{"path":"/collections/{collection_id}","methods":["GET"]},{"path":"/processes","methods":["GET"]},{"path":"/files","methods":["GET"]},{"path":"/files/{path}","methods":["GET","PUT","DELETE"]},{"path":"/result","methods":["POST"]},{"path":"/jobs","methods":["POST","GET"]},{"path":"/jobs/{job_id}","methods":["GET","PATCH","DELETE"]},{"path":"/jobs/{job_id}/logs","methods":["GET"]},{"path":"/jobs/{job_id}/results","methods":["GET","POST"]},{"path":"/services","methods":["GET","POST"]},{"path":"/services/{service_id}","methods":["GET","PATCH","DELETE"]},{"path":"/services/{service_id}/logs","methods":["GET"]},{"path":"/credentials/basic","methods":["GET"]},{"path":"/me","methods":["GET"]},{"path":"/validation","methods":["POST"]},{"path":"/process_graphs","methods":["GET"]},{"path":"/process_graphs/{process_graph_id}","methods":["GET","PUT","DELETE"]}],"billing":{"currency":"USD","default_plan":"free","plans":[FREE_PLAN]},"links":[{"rel":"about","href":"https://earthengine.google.com/","title":"Google Earth Engine Homepage"},{"rel":"terms-of-service","href":"https://earthengine.google.com/terms/","type":"text/html","title":"Google Earth Engine Terms of Service"},{"rel":"privacy-policy","href":"https://policies.google.com/privacy","type":"text/html","title":"Google Privacy Policy"},{"rel":"related","href":"https://github.com/Open-EO/openeo-earthengine-driver","title":"GitHub repository"},{"rel":"version-history","href":TESTBACKEND+"/.well-known/openeo","type":"application/json","title":"Supported API versions"},{"rel":"data","href":TESTBACKENDDIRECT+"/collections","type":"application/json","title":"Datasets"},{"rel":"conformance","href":TESTBACKENDDIRECT+"/conformance","type":"application/json","title":"OGC Conformance classes"}]}; - const TESTCOLLECTION = {"stac_version":"1.0.0","id":"AAFC/ACI","title":"Canada AAFC Annual Crop Inventory","gee:type":"image_collection","description":"Starting in 2009, the Earth Observation Team of the Science and Technology\nBranch (STB) at Agriculture and Agri-Food Canada (AAFC) began the process\nof generating annual crop type digital maps. Focusing on the Prairie\nProvinces in 2009 and 2010, a Decision Tree (DT) based methodology was\napplied using optical (Landsat-5, AWiFS, DMC) and radar (Radarsat-2) based\nsatellite images. Beginning with the 2011 growing season, this activity has\nbeen extended to other provinces in support of a national crop inventory.\nTo date this approach can consistently deliver a crop inventory that meets\nthe overall target accuracy of at least 85% at a final spatial resolution of\n30m (56m in 2009 and 2010).\n","license":"OGL-Canada-2.0","links":[],"keywords":["aafc","canada","crop","landcover"],"providers":[{"name":"Agriculture and Agri-Food Canada","roles":["producer","licensor"],"url":"https://open.canada.ca/data/en/dataset/ba2645d5-4458-414d-b196-6303ac06c1c9"},{"name":"Google Earth Engine","roles":["host"],"url":"https://developers.google.com/earth-engine/datasets/catalog/AAFC_ACI"}],"extent":{"spatial":{"bbox":[[-135.17,36.83,-51.24,62.25]]},"temporal":{"interval":[["2009-01-01T00:00:00Z",null]]}},"summaries":{},"sci:citation":"Agriculture and Agri-Food Canada Annual Crop Inventory. {YEAR}","stac_extensions":["collection-assets"],"cube:dimensions":{"x":{"type":"spatial","axis":"x","extent":[-135.17,-51.24]},"y":{"type":"spatial","axis":"y","extent":[36.83,62.25]},"t":{"type":"temporal","extent":["2009-01-01T00:00:00Z",null]},"bands":{"type":"bands","values":["landcover"]}},"assets":{}}; + const TESTCOLLECTION = {"stac_version":"1.0.0","id":"AAFC/ACI","title":"Canada AAFC Annual Crop Inventory","gee:type":"image_collection","description":"Starting in 2009, the Earth Observation Team of the Science and Technology\nBranch (STB) at Agriculture and Agri-Food Canada (AAFC) began the process\nof generating annual crop type digital maps. Focusing on the Prairie\nProvinces in 2009 and 2010, a Decision Tree (DT) based methodology was\napplied using optical (Landsat-5, AWiFS, DMC) and radar (Radarsat-2) based\nsatellite images. Beginning with the 2011 growing season, this activity has\nbeen extended to other provinces in support of a national crop inventory.\nTo date this approach can consistently deliver a crop inventory that meets\nthe overall target accuracy of at least 85% at a final spatial resolution of\n30m (56m in 2009 and 2010).\n","license":"OGL-Canada-2.0","links":[],"keywords":["aafc","canada","crop","landcover"],"providers":[{"name":"Agriculture and Agri-Food Canada","roles":["producer","licensor"],"url":"https://open.canada.ca/data/en/dataset/ba2645d5-4458-414d-b196-6303ac06c1c9"},{"name":"Google Earth Engine","roles":["host"],"url":"https://developers.google.com/earth-engine/datasets/catalog/AAFC_ACI"}],"extent":{"spatial":{"bbox":[[-135.17,36.83,-51.24,62.25]]},"temporal":{"interval":[["2009-01-01T00:00:00Z","2020-01-01T00:00:00"]]}},"summaries":{},"sci:citation":"Agriculture and Agri-Food Canada Annual Crop Inventory. {YEAR}","stac_extensions":["collection-assets"],"cube:dimensions":{"x":{"type":"spatial","axis":"x","extent":[-135.17,-51.24]},"y":{"type":"spatial","axis":"y","extent":[36.83,62.25]},"t":{"type":"temporal","extent":["2009-01-01T00:00:00Z","2020-01-01T00:00:00"]},"bands":{"type":"bands","values":["landcover"]}},"assets":{}}; const TESTPROCESS = {"id":"min","summary":"Minimum value","description":"Computes the smallest value of an array of numbers, which is is equal to the last element of a sorted (i.e., ordered) version the array.\n\nAn array without non-`null` elements resolves always with `null`.","categories":["math","reducer"],"parameters":[{"name":"data","description":"An array of numbers.","schema":{"type":"array","items":{"type":["number","null"]}}}],"returns":{"description":"The minimum value.","schema":{"type":["number","null"]}},"examples":[{"arguments":{"data":[1,0,3,2]},"returns":0},{"arguments":{"data":[5,2.5,null,-0.7]},"returns":-0.7},{"arguments":{"data":[]},"returns":null}],"links":[{"rel":"about","href":"http://mathworld.wolfram.com/Minimum.html","title":"Minimum explained by Wolfram MathWorld"}]}; @@ -684,7 +684,7 @@ describe('GEE back-end', () => { }); var f; - test('Upload file', async () => { + test.skip('Upload file', async () => { f = await con.getFile(fileName); expect(f instanceof UserFile).toBeTruthy(); expect(f.path).toBe(fileName); @@ -697,7 +697,7 @@ describe('GEE back-end', () => { expect(files[0].path).toBe(f.path); }); - test('Get file contents', (done) => { + test.skip('Get file contents', (done) => { f.retrieveFile().then(resource => { expect(resource).not.toBeNull(); if (isBrowserEnv) { // Browser environment @@ -737,7 +737,7 @@ describe('GEE back-end', () => { }); var target = "downloaded_file.txt"; - test('Download/Save file', async () => { + test.skip('Download/Save file', async () => { if (isBrowserEnv) { // Browser environment // Hard to test a browser download, ignore @@ -758,12 +758,12 @@ describe('GEE back-end', () => { } }) - test('Update file being not supported', async () => { + test.skip('Update file being not supported', async () => { expect(f.updateFile).toBeUndefined(); expect(f.replaceFile).toBeUndefined(); }); - test('Delete file', async () => { + test.skip('Delete file', async () => { await f.deleteFile(); var files = await con.listFiles(); diff --git a/tests/eodc.test.js b/tests/eodc.test.js index 1348257..84e3a63 100644 --- a/tests/eodc.test.js +++ b/tests/eodc.test.js @@ -12,14 +12,14 @@ describe('EODC back-end', () => { describe('Request Collection Items', () => { let con; - test('Connect', async () => { + test.skip('Connect', async () => { con = await OpenEO.connect(TESTBACKEND); expect(con instanceof Connection).toBeTruthy(); let cap = con.capabilities(); expect(cap instanceof Capabilities).toBeTruthy(); }); - test('Check collection', async () => { + test.skip('Check collection', async () => { let col = await con.describeCollection(TESTCOLLECTION); expect(col.id).toBe(TESTCOLLECTION); expect(col).toHaveProperty("links");