fiware-orion-client
Version:
A client Library that makes it easier to get access to Orion Context Broker (part of the FIWARE platform)
924 lines (799 loc) • 26.2 kB
JavaScript
;
// Server must be run with the -multiservice option (multitenant)
const ORION_SERVER = 'http://130.206.83.68:1026/v1';
const ORION_TESTBED_SERVER = 'http://orion.lab.fiware.org:1026/v1';
var Orion = require('../orion-lib'),
OrionClient = new Orion.Client({
url: ORION_SERVER,
userAgent: 'Test'
}),
OrionClientService = new Orion.Client({
url: ORION_SERVER,
userAgent: 'Test',
service: 'Test_Service'
}),
OrionTestBedService = new Orion.Client({
url: ORION_TESTBED_SERVER,
userAgent: 'Test',
token: 'nBA8EYe0wrzI8nVISMLMlR1CpUWfsF'
}),
OrionHelper = Orion.NgsiHelper;
var assert = require('assert');
var fs = require('fs');
const CAR_ID = 'P-9878KLA';
const CAR_TYPE = 'Car';
const PARK_TYPE = 'Park';
const RESTAURANT_TYPE = 'Car';
const VALLADOLID = '/Spain/Valladolid';
const PARKS = 'PublicParks';
const PARK_SERVICE_PATH = VALLADOLID + '/' + PARKS;
const PARK_ID = 'CampoGrande';
var contextData = {
type: CAR_TYPE,
id: CAR_ID,
speed: 98,
rpm: 2000
};
var contextData2 = {
type: CAR_TYPE,
id: '8787GYV',
speed: 120,
rpm: 2500
};
const TARGET_LOCATION = '41.3763726, 2.1864475';
var geoContextData = {
type: RESTAURANT_TYPE,
id: 'r12345',
speed: 135,
location: new Orion.Attribute(TARGET_LOCATION, 'geo:point')
};
// XML Data for testing purposes
var XMLData = require('./xml-data');
function assertEqualObj(obj1, obj2) {
assert.deepEqual(obj1, obj2);
}
describe('NGSI Helper > ', function() {
function assertNgsiObject(obj) {
assert.equal(obj.type, CAR_TYPE);
assert.equal(obj.id, CAR_ID);
assert.equal(obj.isPattern, false);
assert.equal(obj.attributes[0].value, '98');
assert.equal(obj.attributes[1].value, '2000');
}
it('should convert JS objects to NGSI Objects', function() {
var ngsiObj = OrionHelper.toNgsiObject(contextData);
assertNgsiObject(ngsiObj);
});
it('should convert NGSI Objects to XML', function() {
var objAsNgsiXML = OrionHelper.toNgsiObject(contextData).toXML();
assert.equal(objAsNgsiXML, XMLData.contextDataAsXML);
});
it('should parse NGSI Responses', function() {
var jsonChunk = fs.readFileSync(__dirname + '/ngsi-response.json', 'UTF-8');
var object = OrionHelper.parse(jsonChunk);
if (object.inError) {
assert.fail('It cannot be in error');
return;
}
assertEqualObj(contextData, object);
});
it('should parse NGSI Responses - geolocation data', function() {
var jsonChunk = fs.readFileSync(__dirname + '/ngsi-response-location.json', 'UTF-8');
var object = OrionHelper.parse(jsonChunk);
if (object.inError) {
assert.fail('It cannot be in error');
return;
}
assert.equal(object.location.type, 'geo:point');
assert.equal(object.location.value, '34, 48');
assert.equal(!object.metadata, true);
});
it('should parse NGSI Responses - geolocation data - GeoJSON', function() {
var jsonChunk = fs.readFileSync(__dirname + '/ngsi-response-location.json', 'UTF-8');
var options = {
'GeoJSON': true
};
var object = OrionHelper.parse(jsonChunk, options);
if (object.inError) {
assert.fail('It cannot be in error');
return;
}
assert.equal(object.location.type, 'Point');
assert.equal(object.location.coordinates.length, 2);
assert.equal(object.location.coordinates[1], 34);
assert.equal(object.location.coordinates[0], 48);
assert.equal(!object.metadata, true);
});
it('should parse NGSI Responses in XML', function() {
var xmlChunk = fs.readFileSync(__dirname + '/ngsi-response.xml', 'UTF-8');
var object = OrionHelper.parse(xmlChunk);
if (object.inError) {
assert.fail('It cannot be in error');
return;
}
assertEqualObj(contextData, object);
});
it('should parse providing requests in XML', function() {
var out = OrionHelper.parseNgsiRequest(XMLData.requestAsXML);
assert.equal(out.entities.length, 2);
assert.equal(out.attributes.length, 2);
assert.equal(out.entities[0].id, 'Street4');
assert.equal(out.attributes[0], 'temperature');
assert.equal(out.entities[1].type, 'Street');
assert.ok(typeof out.entities[1].pattern === 'undefined');
});
it('should parse providing requests in JSON', function() {
var requestAsJson = {
"contextElements":[
{
"type":"House",
"isPattern":"false",
"id":"Customer-6790",
"attributes":[
{
"name":"boilerStatus",
"type":"string",
"value":"OF"
}
]
}
],
"updateAction":"UPDATE"
};
var out = OrionHelper.parseNgsiRequest(requestAsJson);
assert.equal(out.entities.length, 1);
assert.equal(out.entities[0].id, 'Customer-6790');
assert.equal(out.entities[0].boilerStatus, 'OF');
});
it('should detect NGSI Responses in error', function() {
var jsonChunk = fs.readFileSync(__dirname + '/ngsi-response-error.json',
'UTF-8');
var object = OrionHelper.parse(jsonChunk);
assert.equal(object.inError, true);
assert.equal(object.errorCode, 400);
});
it('should convert objects to NGSI', function() {
var object = contextData;
var ngsiObject = OrionHelper.toNgsi(object);
assertNgsiObject(ngsiObject.contextElements[0]);
});
it('should convert objects to NGSI - geolocation', function() {
var object = geoContextData;
var ngsiObject = OrionHelper.toNgsi(object);
var geoAttr = ngsiObject.contextElements[0].attributes[1];
assert.equal(ngsiObject.contextElements[0].type, RESTAURANT_TYPE);
assert.equal(geoAttr.type, 'coords');
assert.equal(geoAttr.coords, geoContextData.coords);
assert.equal(geoAttr.metadatas[0].value, 'WGS84');
});
it('should build NGSI Responses', function() {
var object = contextData;
var ngsiResponse = OrionHelper.buildNgsiResponse(object);
assertNgsiObject(ngsiResponse.contextResponses[0].contextElement);
assert.equal(ngsiResponse.contextResponses[0].statusCode.code, 200);
});
it('should build NGSI Responses as XML', function() {
var object = contextData;
var ngsiResponse = OrionHelper.buildNgsiResponse(object).toXML();
assert.equal(ngsiResponse, XMLData.contextResponseAsXML);
});
it('should generate query URLs by id', function() {
var query = {
id: '7890'
};
var url = OrionHelper.toURL(query);
assert.equal(url, 'contextEntities/7890');
});
it('should generate query URLs by type', function() {
var query = {
type: 'Car'
};
var url = OrionHelper.toURL(query);
assert.equal(url, 'contextEntityTypes/Car');
});
});
describe('Context Operations > ', function() {
this.timeout(10000);
describe('UPDATE', function(done) {
it('should update context data', function(done) {
OrionClient.updateContext(contextData).then(function(updatedData) {
assertEqualObj(contextData, updatedData);
done();
}).catch(function(err) {
done(err);
});
});
it('should update multiple context data', function(done) {
var dataList = [
contextData,
contextData2
];
OrionClient.updateContext(dataList).then(function(updatedData) {
assertEqualObj(dataList, updatedData);
done();
});
});
it('should update context with entity paths', function(done) {
var data = {
id: PARK_SERVICE_PATH + '/' + PARK_ID,
type: PARK_TYPE,
extension: 2000
};
OrionClient.updateContext(data).then(function(updatedData) {
return OrionClient.queryContext({
type: 'Park',
id: PARK_ID
}, { path: VALLADOLID + '/#' });
}).then(function(queryResult) {
assert.equal(queryResult.extension, 2000);
done();
}).catch(function(err) {
done(err);
});
});
it('should update context with service', function(done) {
// Same as contextData but in a different service and with different speed
// Thus the object will be different
const TEST_SERVICE_SPEED = 400;
var data = {
id: CAR_ID,
type: CAR_TYPE,
speed: TEST_SERVICE_SPEED
};
OrionClientService.updateContext(data).then(function(updatedData) {
return OrionClientService.queryContext({
type: CAR_TYPE,
id: CAR_ID
});
}).then(function(queryResult) {
assert.equal(queryResult.speed, TEST_SERVICE_SPEED);
// Now query the same entity and id but in the default service
return OrionClient.queryContext({
type: CAR_TYPE,
id: CAR_ID
});
}).then(function(queryResult2) {
assert.equal(queryResult2.speed, contextData.speed);
done();
}).catch(function(err) {
done(err);
});
});
it('should reject due to timeout', function(done) {
OrionClient.updateContext(contextData,{
timeout: 1
}).then(function(updatedData) {
done('failed!');
}).catch(function(err) {
done();
});
});
it('should be rejected if a non existing entity is updated',
function(done) {
OrionClient.updateContext({
type: 'test',
id: 'not-exists2',
speed: 100
}, { updateAction: 'UPDATE' }).then(function() {
done('failed!');
}, function(err) {
done();
});
});
it('should delete context entities', function(done) {
var deleteData = {
type: 'test',
id: 'test-1',
testAttr: 'testVal'
};
var deleteQuery = {
type: 'test',
id: 'test-1'
};
OrionClient.updateContext(deleteData).then(function(updatedData) {
return OrionClient.deleteContext(deleteQuery);
}).then(function() {
return OrionClient.queryContext(deleteQuery);
}).then(function(queryResult) {
assert.equal(queryResult, null);
done();
}).catch(function(err) {
done(err);
});
});
}); // UPDATE
describe('QUERY', function() {
var queryParams = {
type: CAR_TYPE,
id: CAR_ID
};
before(function(done) {
OrionClient.updateContext(contextData).then(() => done(), () => done());
});
it('should query context data', function(done) {
OrionClient.queryContext(queryParams).then(function(retrievedData) {
assertEqualObj(contextData, retrievedData);
done();
}).catch(function(err) {
done(err);
});
});
it('should query multiple context data by id', function(done) {
OrionClient.updateContext(contextData2).then(function() {
return OrionClient.queryContext([
{
id: contextData.id,
},
{
id: contextData2.id
}
]);
}).then(function(result) {
assert.equal(result.length, 2);
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data using a token', function(done) {
var tokenQuery = {
id: 'urn:smartsantander:testbed:357'
};
OrionTestBedService.queryContext(tokenQuery).then(function(retrievedData) {
assert.equal(retrievedData.type, 'santander:soundacc');
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data by location - circle', function(done) {
var geoQuery = {
type: RESTAURANT_TYPE
};
var locationOptions = {
location: {
coords: TARGET_LOCATION,
geometry: 'Circle',
radius: 1000
}
};
OrionClient.updateContext(geoContextData).then(function() {
return OrionClient.queryContext(geoQuery, locationOptions);
}).then(function(retrievedData) {
assert.equal(retrievedData.id, 'r12345');
assert.equal(retrievedData.location.value, TARGET_LOCATION);
assert.equal(retrievedData.location.type, 'geo:point');
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data by location - circle - GeoJSON', function(done) {
var geoQuery = {
type: RESTAURANT_TYPE
};
var locationOptions = {
location: {
coords: TARGET_LOCATION,
geometry: 'Circle',
radius: 1000
},
GeoJSON: true
};
OrionClient.updateContext(geoContextData).then(function() {
return OrionClient.queryContext(geoQuery, locationOptions);
}).then(function(retrievedData) {
assert.equal(retrievedData.id, 'r12345');
assert.equal(retrievedData.location.coordinates[1], 41.3763726);
assert.equal(retrievedData.location.coordinates[0], 2.1864475);
assert.equal(retrievedData.location.type, 'Point');
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data by location - inverted', function(done) {
var geoQuery = {
type: RESTAURANT_TYPE
};
var locationOptions = {
location: {
coords: TARGET_LOCATION,
geometry: 'Circle;external',
radius: 1000
}
};
OrionClient.queryContext(geoQuery, locationOptions).then(function(retrievedData) {
assert.equal(retrievedData, null);
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data by location - polygon', function(done) {
var geoQuery = {
type: RESTAURANT_TYPE
};
var locationOptions = {
location: {
// Roughly speaking a polygon which denotes Spain
coords: '42.90,-9.26, 42.35,1.45, 37.21,-7.40, 37.98,-1.15',
geometry: 'Polygon'
}
};
OrionClient.queryContext(geoQuery, locationOptions).then(function(retrievedData) {
assert.equal(retrievedData, null);
done();
}).catch(function(err) {
done(err);
});
});
it('should query context data by filtering it', function(done) {
var query = {
type: CAR_TYPE
};
var carData = {
type: CAR_TYPE,
id: '12345G',
speed: 135,
brand: 'Mercedes'
};
OrionClient.updateContext(carData).then(function() {
return OrionClient.queryContext(query, {
q: 'brand == Mercedes'
});
}).then(function(result) {
assert.equal(result.id, carData.id);
done();
}).catch(function(error) {
done(error);
});
});
it('should query context data with associated metadata', function(done) {
var contextData2 = {
type: CAR_TYPE,
id: '8787GYH',
speed: new Orion.Attribute(120, 'Speed', {
accuracy: 0.9
})
};
OrionClient.updateContext(contextData2).then(function() {
return OrionClient.queryContext({
type: CAR_TYPE,
id: '8787GYH'
});
}).then(function(retrievedData) {
assert.equal(retrievedData.speed.value, 120);
assert.equal(retrievedData.speed.metadata.accuracy, 0.9);
done();
}).catch(function(error) {
done(error);
});
});
it('should query context data with date as metadata', function(done) {
var date = new Date();
var contextData3 = {
type: CAR_TYPE,
id: '9999GYH',
speed: new Orion.Attribute(150, 'Speed', {
timestamp: date
})
};
OrionClient.updateContext(contextData3).then(function() {
return OrionClient.queryContext({
type: CAR_TYPE,
id: '9999GYH'
});
}).then(function(retrievedData) {
assert.equal(retrievedData.speed.value, 150);
assert.equal(retrievedData.speed.metadata.timestamp.getTime(),
date.getTime());
done();
}).catch(function(error) {
done(error);
});
});
it('should query context data with date as data', function(done) {
var date = new Date();
var contextData3 = {
type: CAR_TYPE,
id: '1111GYH',
timestamp: date
};
OrionClient.updateContext(contextData3).then(function() {
return OrionClient.queryContext({
type: CAR_TYPE,
id: '1111GYH'
});
}).then(function(retrievedData) {
assert.equal(retrievedData.timestamp.getTime(), date.getTime());
done();
}).catch(function(error) {
done(error);
});
});
it('should query context data with limit and offset', function(done) {
OrionClient.queryContext({
type: CAR_TYPE
}, {
offset: 0,
limit: 1
}).then(function(data) {
// As limit is one the library returns the object directly
assert.equal(typeof data, 'object');
done();
}).catch(function(error) {
done(error);
});
});
it('should query context data with attribute restriction', function(done) {
queryParams.attributes = ['speed'];
OrionClient.queryContext(queryParams).then(function(retrievedData) {
assert.equal(typeof retrievedData.rpm, 'undefined');
done();
}).catch(function(err) {
done(err);
});
});
it('should return null if no element is found', function(done) {
var noMatch = {
type: CAR_TYPE,
id: '123456'
};
OrionClient.queryContext(noMatch).then(function(retrievedData) {
assert.equal(retrievedData, null);
done();
}).catch(function(err) {
done(err);
});
});
describe('QUERY pattern', function() {
var contextData = [
{
type: 'City',
id: 'Spain-Madrid',
currentTemperature: 25.6,
estimatedTemperature: 28
},
{
type: 'City',
id: 'Spain-Valladolid',
currentTemperature: 21.8,
estimatedTemperature: 23
}
];
before(function(done) {
OrionClient.updateContext(contextData).then(() => done(), () => done());
});
var queryParams = {
pattern: 'Spain-*',
type: 'City'
};
it('should return a collection which matches a pattern', function(done) {
OrionClient.queryContext(queryParams).then(function(retrievedData) {
assert.equal(retrievedData.length, 2);
assertEqualObj(retrievedData[0], contextData[0]);
assertEqualObj(retrievedData[1], contextData[1]);
done();
}).catch(function(error) {
done(error);
});
});
it('should return an empty collection if no object matches',
function(done) {
var noMatches = {
type: 'City',
pattern: 'France-*'
};
OrionClient.queryContext(noMatches).then(function(retrievedData) {
assert.equal(retrievedData.length, 0);
done();
}).catch(function(error) {
done(error);
});
});
});
}); // QUERY
describe('SUBSCRIBE', function() {
var entity = {
type: CAR_TYPE,
id: CAR_ID
};
var subscrParams = {
callback: 'http://130.206.83.68/orion/notif_test',
type: 'ONCHANGE', // By default if nothing said
attributes: ['speed']
};
it('should subscribe properly to an existent entity', function(done) {
OrionClient.subscribeContext(entity, subscrParams).then(
function(subscription) {
assert.equal(typeof subscription.subscriptionId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should update an existing subscription', function(done) {
var subscriptionId;
OrionClient.subscribeContext(entity, subscrParams).then(
function(subscription) {
subscriptionId = subscription.subscriptionId;
var updateParams = Object.create(subscrParams);
updateParams.subscriptionId = subscriptionId;
return OrionClient.subscribeContext(entity, updateParams);
}).then(function(updatedSubscription) {
assert.equal(updatedSubscription.subscriptionId, subscriptionId);
done();
}).catch(function(err) {
done(err);
});
});
it('should return error 404 if updating a non existent subscription',
function(done) {
var params = Object.create(subscrParams);
params.subscriptionId = '000000000000000000000000';
OrionClient.subscribeContext(entity, params).then(function() {
done('failed!');
}).catch(function(err) {
assert.equal(err.code, 404);
done();
});
});
it('should subscribe properly filtering by attribute', function(done) {
var entityAttr = {
type: CAR_TYPE,
id: CAR_ID,
attributes: ['speed']
};
OrionClient.subscribeContext(entityAttr, subscrParams).then(
function(subscription) {
assert.equal(typeof subscription.subscriptionId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should subscribe properly by providing a pattern', function(done) {
var entityAttr = {
type: CAR_TYPE,
pattern: '.*',
attributes: ['speed']
};
OrionClient.subscribeContext(entityAttr, subscrParams).then(
function(subscription) {
assert.equal(typeof subscription.subscriptionId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should subscribe to a list of entities', function(done) {
var entities = [{
type: CAR_TYPE,
id: CAR_ID
},
{
type: CAR_TYPE,
id: '8787GV'
}
];
subscrParams.attributes = [
'speed',
'rpm'
];
OrionClient.subscribeContext(entities, subscrParams).then(
function(subscription) {
assert.equal(typeof subscription.subscriptionId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
}); // SUBSCRIBE
describe('REGISTER', function() {
var entity = {
type: CAR_TYPE,
id: CAR_ID,
attributes: [{
name: 'buildYear',
type: typeof ''
}]
};
var registrationParams = {
callback: 'http://localhost/orion/provider'
};
it('should register a context provider', function(done) {
OrionClient.registerContext(entity, registrationParams).then(
function(registration) {
assert.equal(typeof registration.registrationId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should update an existing registration', function(done) {
var params = Object.create(registrationParams);
var registrationId;
OrionClient.registerContext(entity, registrationParams).then(
function(registration) {
registrationId = registration.registrationId;
params.registrationId = registrationId;
return OrionClient.registerContext(entity, params);
}).then(function(registration) {
assert.equal(registration.registrationId, registrationId);
done();
}).catch(function(err) {
done(err);
});
});
it('should reject with error code 404 if updating non existent',
function(done) {
var params = Object.create(registrationParams);
params.registrationId = '000000000000000000000000';
OrionClient.registerContext(entity, params).then(
function(registration) {
done('should fail!');
}).catch(function(err) {
assert.equal(err.code, 404);
done();
});
});
it('should register a context provider. simplified attribute naming',
function(done) {
var registration = {
type: CAR_TYPE,
id: 'M-45678',
attributes: [
'byDefaultString'
]
};
OrionClient.registerContext(entity, registrationParams).then(
function(registration) {
assert.equal(typeof registration.registrationId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should register a context provider. pattern provided', function(done) {
var entityDesc = {
type: CAR_TYPE,
pattern: '*',
attributes: [{
name: 'buildYear',
type: typeof ''
}]
};
OrionClient.registerContext(entityDesc, registrationParams).then(
function(registration) {
assert.equal(typeof registration.registrationId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
it('should register a context provider for various entities',
function(done) {
// This time the attributes will be passed as registration params
registrationParams.attributes = [{
name: 'buildYear',
type: typeof ''
}];
delete entity.attributes;
var entities = [
entity,
{
type: CAR_TYPE,
id: '8787GYV'
}
];
OrionClient.registerContext(entities, registrationParams).then(
function(registration) {
assert.equal(typeof registration.registrationId, 'string');
done();
}).catch(function(err) {
done(err);
});
});
}); // REGISTER
});