feat(rotatingMachine): resolve supplier+type from asset registry, drop denormalized fields
specificClass._setupCurves now calls assetResolver.resolveAssetMetadata to derive supplier/type/units from the model id, instead of trusting denormalized fields on the node config. If the model isn't in the registry, installs a null-predictor stub and logs a clear "pick a model from the asset menu" error rather than crashing. rotatingMachine.html: defaults block trimmed (supplier/category/assetType were stale copies of registry data). Tests: - New test/basic/assetMetadata.basic.test.js covers the registry-resolve path and the missing-model fallback. - nodeClass-config / error-paths / nodeClass-routing / factories / abort-deadlock fixtures updated to the trimmed asset shape. - 209/209 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
61
test/basic/assetMetadata.basic.test.js
Normal file
61
test/basic/assetMetadata.basic.test.js
Normal file
@@ -0,0 +1,61 @@
|
||||
'use strict';
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const Machine = require('../../src/specificClass');
|
||||
|
||||
// Phase 4 regression: after the AssetResolver cutover the node must
|
||||
// (a) derive supplier/type/units from the registry, not from saved config,
|
||||
// (b) hard-fail with a clear log if asset.model is missing,
|
||||
// (c) hard-fail if asset.unit is missing or not in registry's allowed set,
|
||||
// (d) succeed with a known good model + unit.
|
||||
|
||||
function makeConfig({ model = 'hidrostal-H05K-S03R', unit = 'm3/h' } = {}) {
|
||||
return {
|
||||
general: { id: 'test-node', name: 'Pump-T', logging: { enabled: false } },
|
||||
asset: { model, unit, curveUnits: { pressure: 'mbar', flow: unit, power: 'kW', control: '%' } },
|
||||
functionality: { softwareType: 'rotatingmachine' },
|
||||
};
|
||||
}
|
||||
|
||||
test('asset metadata is derived from the registry, not from config', () => {
|
||||
const m = new Machine(makeConfig());
|
||||
assert.ok(m.assetMetadata, 'expected assetMetadata to be populated');
|
||||
assert.equal(m.assetMetadata.supplier, 'Hidrostal');
|
||||
assert.equal(m.assetMetadata.type, 'Centrifugal');
|
||||
assert.ok(Array.isArray(m.assetMetadata.units));
|
||||
assert.ok(m.assetMetadata.units.length > 0);
|
||||
});
|
||||
|
||||
test('valid model + unit yields working curve predictors', () => {
|
||||
const m = new Machine(makeConfig());
|
||||
assert.equal(m.hasCurve, true);
|
||||
assert.equal(typeof m.predictFlow, 'object');
|
||||
assert.equal(typeof m.predictPower, 'object');
|
||||
});
|
||||
|
||||
test('missing model installs null predictors (degraded mode)', () => {
|
||||
const m = new Machine(makeConfig({ model: null }));
|
||||
assert.equal(m.hasCurve, false);
|
||||
assert.equal(m.predictFlow, null);
|
||||
assert.equal(m.predictPower, null);
|
||||
});
|
||||
|
||||
test('unknown model installs null predictors and logs', () => {
|
||||
const m = new Machine(makeConfig({ model: 'no-such-model-xyz' }));
|
||||
assert.equal(m.hasCurve, false);
|
||||
assert.equal(m.assetMetadata, null);
|
||||
});
|
||||
|
||||
test('unit not in registry allowed-set installs null predictors', () => {
|
||||
const m = new Machine(makeConfig({ unit: 'furlongs-per-fortnight' }));
|
||||
assert.equal(m.hasCurve, false);
|
||||
});
|
||||
|
||||
test('two machines with the same model get independent assetMetadata instances', () => {
|
||||
const a = new Machine(makeConfig());
|
||||
const b = new Machine(makeConfig());
|
||||
assert.notStrictEqual(a, b);
|
||||
assert.equal(a.assetMetadata.supplier, b.assetMetadata.supplier);
|
||||
});
|
||||
@@ -9,13 +9,13 @@ const { makeNodeStub, makeREDStub } = require('../helpers/factories');
|
||||
// validated merged shape) and the source's runtime mode. No private hooks.
|
||||
|
||||
function makeUiConfig(overrides = {}) {
|
||||
// After the AssetResolver cutover, the editor no longer saves
|
||||
// supplier/category/assetType — those are derived from the model id via
|
||||
// assetResolver.resolveAssetMetadata at runtime.
|
||||
return {
|
||||
unit: 'm3/h',
|
||||
enableLog: false,
|
||||
logLevel: 'error',
|
||||
supplier: 'hidrostal',
|
||||
category: 'machine',
|
||||
assetType: 'pump',
|
||||
model: 'hidrostal-H05K-S03R',
|
||||
curvePressureUnit: 'mbar',
|
||||
curveFlowUnit: 'm3/h',
|
||||
|
||||
@@ -6,9 +6,9 @@ const NodeClass = require('../../src/nodeClass');
|
||||
const { makeMachineConfig, makeStateConfig, makeNodeStub, makeREDStub } = require('../helpers/factories');
|
||||
|
||||
function makeUiConfig(overrides = {}) {
|
||||
// Post-AssetResolver: editor saves only model + unit + uuid/tagCode.
|
||||
return {
|
||||
unit: 'm3/h', enableLog: false, logLevel: 'error',
|
||||
supplier: 'hidrostal', category: 'machine', assetType: 'pump',
|
||||
model: 'hidrostal-H05K-S03R',
|
||||
curvePressureUnit: 'mbar', curveFlowUnit: 'm3/h',
|
||||
curvePowerUnit: 'kW', curveControlUnit: '%',
|
||||
|
||||
@@ -11,13 +11,12 @@ const { makeNodeStub, makeREDStub } = require('../helpers/factories');
|
||||
// source, and instrumented domain methods.
|
||||
|
||||
function makeUiConfig(overrides = {}) {
|
||||
// Post-AssetResolver: editor saves only model + unit + uuid/tagCode.
|
||||
// supplier/category/assetType are derived at runtime.
|
||||
return {
|
||||
unit: 'm3/h',
|
||||
enableLog: false,
|
||||
logLevel: 'error',
|
||||
supplier: 'hidrostal',
|
||||
category: 'machine',
|
||||
assetType: 'pump',
|
||||
model: 'hidrostal-H05K-S03R',
|
||||
curvePressureUnit: 'mbar',
|
||||
curveFlowUnit: 'm3/h',
|
||||
|
||||
@@ -11,10 +11,11 @@ function makeMachineConfig(overrides = {}) {
|
||||
functionality: {
|
||||
positionVsParent: 'atEquipment',
|
||||
},
|
||||
// Post-AssetResolver: only model + unit + tagCode/uuid are saved on the
|
||||
// node. supplier/category/type are derived from the registry. Keeping
|
||||
// legacy fields in the factory would trip the strict-cutover guard in
|
||||
// nodeClass.buildDomainConfig.
|
||||
asset: {
|
||||
supplier: 'hidrostal',
|
||||
category: 'machine',
|
||||
type: 'pump',
|
||||
model: 'hidrostal-H05K-S03R',
|
||||
unit: 'm3/h',
|
||||
curveUnits: {
|
||||
|
||||
@@ -36,8 +36,7 @@ function machineConfig() {
|
||||
general: { id: 'p1', name: 'p1', unit: 'm3/h',
|
||||
logging: { enabled: false, logLevel: 'error' } },
|
||||
functionality: { softwareType: 'machine', role: 'rotationaldevicecontroller' },
|
||||
asset: { category: 'pump', type: 'centrifugal',
|
||||
model: 'hidrostal-H05K-S03R', supplier: 'hidrostal' },
|
||||
asset: { model: 'hidrostal-H05K-S03R', unit: 'm3/h' },
|
||||
mode: {
|
||||
current: 'auto',
|
||||
allowedActions: { auto: ['execsequence', 'execmovement', 'flowmovement', 'statuscheck'] },
|
||||
|
||||
Reference in New Issue
Block a user