Ensure a request for telemetry happens in Condition Sets (#7592)

* request telemetry when subscribing to data in case we have cached subscription

* change back to >=

* revert

* update tests

* fixing tests

* add metadata

* fix test

* another mock required

* one more function needed

* attempt to fix some afterall errors

* add fixme for e2e test

* fail fast on request

---------

Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Scott Bell 2024-03-19 18:44:50 +01:00 committed by GitHub
parent fb396ac194
commit e305b46d88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 120 additions and 62 deletions

View File

@ -457,4 +457,11 @@ test.describe('Basic Condition Set Use', () => {
await page.goto(exampleTelemetry.url);
});
test.fixme('Ensure condition sets work with telemetry like operator status', ({ page }) => {
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/nasa/openmct/issues/7484'
});
});
});

View File

@ -56,20 +56,38 @@ export default class ConditionManager extends EventEmitter {
);
}
subscribeToTelemetry(endpoint) {
const id = this.openmct.objects.makeKeyString(endpoint.identifier);
if (this.subscriptions[id]) {
console.log('subscription already exists');
async requestLatestValue(endpoint) {
const options = {
size: 1,
strategy: 'latest'
};
const latestData = await this.openmct.telemetry.request(endpoint, options);
if (!latestData) {
throw new Error('Telemetry request failed by returning a falsy response');
}
if (latestData.length === 0) {
return;
}
this.telemetryReceived(endpoint, latestData[0]);
}
subscribeToTelemetry(endpoint) {
const telemetryKeyString = this.openmct.objects.makeKeyString(endpoint.identifier);
if (this.subscriptions[telemetryKeyString]) {
return;
}
const metadata = this.openmct.telemetry.getMetadata(endpoint);
this.telemetryObjects[id] = Object.assign({}, endpoint, {
this.telemetryObjects[telemetryKeyString] = Object.assign({}, endpoint, {
telemetryMetaData: metadata ? metadata.valueMetadatas : []
});
this.subscriptions[id] = this.openmct.telemetry.subscribe(
// get latest telemetry value (in case subscription is cached and no new data is coming in)
this.requestLatestValue(endpoint);
this.subscriptions[telemetryKeyString] = this.openmct.telemetry.subscribe(
endpoint,
this.telemetryReceived.bind(this, endpoint)
);
@ -91,7 +109,7 @@ export default class ConditionManager extends EventEmitter {
//force re-computation of condition set result as we might be in a state where
// there is no telemetry datum coming in for a while or at all.
let latestTimestamp = getLatestTimestamp(
const latestTimestamp = getLatestTimestamp(
{},
{},
this.timeSystems,
@ -334,57 +352,54 @@ export default class ConditionManager extends EventEmitter {
return currentCondition;
}
requestLADConditionSetOutput(options) {
async requestLADConditionSetOutput(options) {
if (!this.conditions.length) {
return Promise.resolve([]);
return [];
}
return this.compositionLoad.then(() => {
let latestTimestamp;
let conditionResults = {};
let nextLegOptions = { ...options };
delete nextLegOptions.onPartialResponse;
await this.compositionLoad;
const conditionRequests = this.conditions.map((condition) =>
condition.requestLADConditionResult(nextLegOptions)
let latestTimestamp;
let conditionResults = {};
let nextLegOptions = { ...options };
delete nextLegOptions.onPartialResponse;
const results = Promise.all(
this.conditions.map((condition) => condition.requestLADConditionResult(nextLegOptions))
);
results.forEach((resultObj) => {
const {
id,
data,
data: { result }
} = resultObj;
if (this.findConditionById(id)) {
conditionResults[id] = Boolean(result);
}
latestTimestamp = getLatestTimestamp(
latestTimestamp,
data,
this.timeSystems,
this.openmct.time.timeSystem()
);
return Promise.all(conditionRequests).then((results) => {
results.forEach((resultObj) => {
const {
id,
data,
data: { result }
} = resultObj;
if (this.findConditionById(id)) {
conditionResults[id] = Boolean(result);
}
latestTimestamp = getLatestTimestamp(
latestTimestamp,
data,
this.timeSystems,
this.openmct.time.timeSystem()
);
});
if (!Object.values(latestTimestamp).some((timeSystem) => timeSystem)) {
return [];
}
const currentCondition = this.getCurrentConditionLAD(conditionResults);
const currentOutput = Object.assign(
{
output: currentCondition.configuration.output,
id: this.conditionSetDomainObject.identifier,
conditionId: currentCondition.id
},
latestTimestamp
);
return [currentOutput];
});
});
if (!Object.values(latestTimestamp).some((timeSystem) => timeSystem)) {
return [];
}
const currentCondition = this.getCurrentConditionLAD(conditionResults);
const currentOutput = {
output: currentCondition.configuration.output,
id: this.conditionSetDomainObject.identifier,
conditionId: currentCondition.id,
...latestTimestamp
};
return [currentOutput];
}
isTelemetryUsed(endpoint) {
@ -409,7 +424,7 @@ export default class ConditionManager extends EventEmitter {
}
const normalizedDatum = this.createNormalizedDatum(datum, endpoint);
const timeSystemKey = this.openmct.time.timeSystem().key;
const timeSystemKey = this.openmct.time.getTimeSystem().key;
let timestamp = {};
const currentTimestamp = normalizedDatum[timeSystemKey];
timestamp[timeSystemKey] = currentTimestamp;

View File

@ -40,12 +40,10 @@ export default class ConditionSetTelemetryProvider {
return domainObject.type === 'conditionSet';
}
request(domainObject, options) {
async request(domainObject, options) {
let conditionManager = this.getConditionManager(domainObject);
return conditionManager.requestLADConditionSetOutput(options).then((latestOutput) => {
return latestOutput;
});
let latestOutput = await conditionManager.requestLADConditionSetOutput(options);
return latestOutput;
}
subscribe(domainObject, callback) {

View File

@ -66,7 +66,8 @@ describe('the plugin', function () {
format: 'utc',
hints: {
domain: 1
}
},
source: 'utc'
},
{
key: 'testSource',
@ -720,6 +721,23 @@ describe('the plugin', function () {
});
it('should evaluate as old when telemetry is not received in the allotted time', (done) => {
openmct.telemetry = jasmine.createSpyObj('telemetry', [
'subscribe',
'getMetadata',
'request',
'getValueFormatter',
'abortAllRequests'
]);
openmct.telemetry.getMetadata.and.returnValue({
...testTelemetryObject.telemetry,
valueMetadatas: []
});
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
openmct.telemetry.getValueFormatter.and.returnValue({
parse: function (value) {
return value;
}
});
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
conditionMgr.on('conditionSetResultUpdated', mockListener);
conditionMgr.telemetryObjects = {
@ -741,6 +759,20 @@ describe('the plugin', function () {
});
it('should not evaluate as old when telemetry is received in the allotted time', (done) => {
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
openmct.telemetry.getMetadata.and.returnValue({
...testTelemetryObject.telemetry,
valueMetadatas: testTelemetryObject.telemetry.values
});
const testDatum = {
'some-key2': '',
utc: 1,
testSource: '',
'some-key': null,
id: 'test-object'
};
openmct.telemetry.request = jasmine.createSpy('request');
openmct.telemetry.request.and.returnValue(Promise.resolve([testDatum]));
const date = 1;
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input =
['0.4'];
@ -750,9 +782,7 @@ describe('the plugin', function () {
'test-object': testTelemetryObject
};
conditionMgr.updateConditionTelemetryObjects();
conditionMgr.telemetryReceived(testTelemetryObject, {
utc: date
});
conditionMgr.telemetryReceived(testTelemetryObject, testDatum);
setTimeout(() => {
expect(mockListener).toHaveBeenCalledWith({
output: 'Default',
@ -868,6 +898,12 @@ describe('the plugin', function () {
it('should stop evaluating conditions when a condition evaluates to true', () => {
const date = Date.now();
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
openmct.telemetry.getMetadata.and.returnValue({
...testTelemetryObject.telemetry,
valueMetadatas: []
});
conditionMgr.on('conditionSetResultUpdated', mockListener);
conditionMgr.telemetryObjects = {
'test-object': testTelemetryObject

View File

@ -169,6 +169,8 @@ describe('Notebook plugin:', () => {
openmct.editor = {};
openmct.editor.isEditing = () => false;
openmct.editor.on = () => {};
openmct.editor.off = () => {};
const applicableViews = openmct.objectViews.get(notebookViewObject, [notebookViewObject]);
notebookViewProvider = applicableViews.find(