Skip to content

Commit 79a304c

Browse files
committed
refactor out logic for updating runstate and runstate pvs and add tests for this
1 parent c98ebb2 commit 79a304c

File tree

5 files changed

+173
-40
lines changed

5 files changed

+173
-40
lines changed

app/components/InstrumentPage.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
IfcGroup,
1717
IfcPVWSMessage,
1818
IfcPVWSRequest,
19+
instList,
1920
PVWSRequestType,
2021
} from "@/app/types";
2122
import {
@@ -106,7 +107,7 @@ export function toPrecision(
106107
function InstrumentData({ instrumentName }: { instrumentName: string }) {
107108
const [showHiddenBlocks, setShowHiddenBlocks] = useState(false);
108109
const CONFIG_DETAILS = "CS:BLOCKSERVER:GET_CURR_CONFIG_DETAILS";
109-
const [instlist, setInstlist] = useState<Array<any> | null>(null);
110+
const [instlist, setInstlist] = useState<instList | null>(null);
110111
const [currentInstrument, setCurrentInstrument] = useState<Instrument | null>(
111112
null,
112113
);
@@ -140,8 +141,8 @@ function InstrumentData({ instrumentName }: { instrumentName: string }) {
140141
let prefix = "";
141142

142143
for (const item of instlist) {
143-
if (item["name"] == instName.toUpperCase()) {
144-
prefix = item["pvPrefix"];
144+
if (item.name == instName.toUpperCase()) {
145+
prefix = item.pvPrefix;
145146
}
146147
}
147148
if (!prefix) {

app/instruments/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export default function createInstrumentGroupsFromInstlist(
55
): Map<string, Array<string>> {
66
let newInstrumentGroups: Map<string, Array<string>> = new Map();
77
for (let inst of jsonInstList) {
8-
for (let group of inst["groups"]) {
8+
for (let group of inst.groups) {
99
if (!newInstrumentGroups.has(group)) {
1010
newInstrumentGroups.set(group, []);
1111
}
12-
newInstrumentGroups.get(group)!.push(inst["name"]);
12+
newInstrumentGroups.get(group)!.push(inst.name);
1313
}
1414
}
1515
return newInstrumentGroups;

app/wall/page.tsx

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import { instListFromBytes } from "../components/dehex_and_decompress";
55
import InstrumentGroup from "./components/InstrumentGroup";
66
import ShowHideBeamInfo from "./components/ShowHideBeamInfo";
77
import JenkinsJobIframe from "./components/JenkinsJobsIframe";
8-
import {
9-
IfcPVWSMessage,
10-
IfcPVWSRequest,
11-
PVWSRequestType,
12-
targetStation,
13-
} from "@/app/types";
8+
import { IfcPVWSMessage, IfcPVWSRequest, targetStation } from "@/app/types";
149
import { instListPV, instListSubscription, socketURL } from "@/app/commonVars";
10+
import {
11+
updateInstrumentRunstate,
12+
updateInstrumentRunstatePV,
13+
} from "@/app/wall/utils";
1514

1615
export default function WallDisplay() {
1716
const runstatePV = "DAE:RUNSTATE_STR";
@@ -131,40 +130,19 @@ export default function WallDisplay() {
131130

132131
if (updatedPVName == instListPV && updatedPVbytes != null) {
133132
const instListDict = instListFromBytes(updatedPVbytes);
134-
for (const item of instListDict) {
135-
// Iterate through instruments in the instlist, get the runstate PV and subscribe
136-
const instName = item["name"];
137-
const instPrefix = item["pvPrefix"];
133+
for (const instrument of instListDict) {
138134
setData((prev) => {
139-
const newData: Array<targetStation> = [...prev];
140-
newData.map((targetStation) => {
141-
const foundInstrument = targetStation.instruments.find(
142-
(instrument) => instrument.name === instName,
143-
);
144-
if (foundInstrument) {
145-
foundInstrument.runstatePV = instPrefix + runstatePV;
146-
// Subscribe to the instrument's runstate PV
147-
sendJsonMessage({
148-
type: PVWSRequestType.subscribe,
149-
pvs: [foundInstrument.runstatePV],
150-
});
151-
}
152-
});
153-
return newData;
135+
return updateInstrumentRunstatePV(
136+
prev,
137+
instrument,
138+
runstatePV,
139+
sendJsonMessage,
140+
);
154141
});
155142
}
156143
} else if (updatedPVvalue) {
157144
setData((prev) => {
158-
const newData: Array<targetStation> = [...prev];
159-
newData.map((targetStation) => {
160-
const foundInstrument = targetStation.instruments.findIndex(
161-
(instrument) => instrument.runstatePV === updatedPVName,
162-
);
163-
if (foundInstrument !== -1)
164-
targetStation.instruments[foundInstrument].runstate =
165-
updatedPVvalue;
166-
});
167-
return newData;
145+
return updateInstrumentRunstate(prev, updatedPVName, updatedPVvalue);
168146
});
169147
}
170148
}, [lastJsonMessage, sendJsonMessage]);

app/wall/utils.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import {
2+
updateInstrumentRunstate,
3+
updateInstrumentRunstatePV,
4+
} from "@/app/wall/utils";
5+
import { IfcInstrumentStatus, instListEntry, targetStation } from "@/app/types";
6+
7+
test("updateInstrumentRunstate returns new array with runstate of instrument changed", () => {
8+
const instrumentName = "anInstrumentName";
9+
const runStatePV = "AN:INST:DAE:RUNSTATE";
10+
const instrument: IfcInstrumentStatus = {
11+
name: instrumentName,
12+
runstatePV: runStatePV,
13+
};
14+
const original: targetStation = {
15+
targetStation: "Target station -1",
16+
instruments: [instrument],
17+
};
18+
const expectedValue = "RUNNING";
19+
expect(
20+
updateInstrumentRunstate([original], runStatePV, expectedValue)[0]
21+
.instruments[0].runstate,
22+
).toBe(expectedValue);
23+
});
24+
test("updateInstrumentRunstate returns untouched array if runstate PV is not found", () => {
25+
const runStatePV = "AN:INST:DAE:RUNSTATE";
26+
const instrument: IfcInstrumentStatus = {
27+
name: "notThatInstrument",
28+
runstatePV: "BLAH",
29+
};
30+
const original: targetStation = {
31+
targetStation: "Target station 42",
32+
instruments: [instrument],
33+
};
34+
const expectedValue = "RUNNING";
35+
expect(
36+
updateInstrumentRunstate([original], runStatePV, expectedValue)[0]
37+
.instruments[0].runstate,
38+
).toBe(undefined);
39+
});
40+
41+
test("updateInstrumentRunstatePV returns untouched array if instrument is not found", () => {
42+
const runStatePvThatShouldNeverGetUsed = "INV:RUNSTATE";
43+
const mockSendJsonMessage = jest.fn();
44+
const invalidInstrument: instListEntry = {
45+
name: "invalidInstrument",
46+
groups: [],
47+
pvPrefix: "invalidPrefix",
48+
isScheduled: true,
49+
seci: false,
50+
hostName: "invalidHostname",
51+
};
52+
const original: targetStation = {
53+
targetStation: "Target station 3",
54+
instruments: [],
55+
};
56+
const returned = updateInstrumentRunstatePV(
57+
[original],
58+
invalidInstrument,
59+
runStatePvThatShouldNeverGetUsed,
60+
mockSendJsonMessage,
61+
);
62+
expect(returned[0].instruments.length).toBe(0);
63+
expect(mockSendJsonMessage).toHaveBeenCalledTimes(0);
64+
});
65+
66+
test("updateInstrumentRunstatePV returns new array with runstate PV updated and subscribed to", () => {
67+
const runStatePvThatShouldGetUsed = "NEW:RUNSTATE";
68+
const mockSendJsonMessage = jest.fn();
69+
const inst: instListEntry = {
70+
name: "instrument",
71+
groups: [],
72+
pvPrefix: "prefix",
73+
isScheduled: true,
74+
seci: false,
75+
hostName: "hostname",
76+
};
77+
const original: targetStation = {
78+
targetStation: "Target station 4",
79+
instruments: [inst],
80+
};
81+
const returned = updateInstrumentRunstatePV(
82+
[original],
83+
inst,
84+
runStatePvThatShouldGetUsed,
85+
mockSendJsonMessage,
86+
);
87+
expect(returned[0].instruments.length).toBe(1);
88+
expect(returned[0].instruments[0].runstatePV).toBe(
89+
inst.pvPrefix + runStatePvThatShouldGetUsed,
90+
);
91+
expect(mockSendJsonMessage).toHaveBeenCalledTimes(1);
92+
expect(mockSendJsonMessage).toHaveBeenCalledWith({
93+
type: "subscribe",
94+
pvs: [inst.pvPrefix + runStatePvThatShouldGetUsed],
95+
});
96+
});

app/wall/utils.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {
2+
IfcPVWSRequest,
3+
instListEntry,
4+
PVWSRequestType,
5+
targetStation,
6+
} from "@/app/types";
7+
8+
/**
9+
* Copy the original array, update the given runstate PV's runstate value, then return the copied array.
10+
* @param prev the previous array of target stations, containing instruments.
11+
* @param updatedPVName the runstate PV address
12+
* @param updatedPVvalue the runstate
13+
*/
14+
export function updateInstrumentRunstate(
15+
prev: Array<targetStation>,
16+
updatedPVName: string,
17+
updatedPVvalue: string,
18+
) {
19+
const newData: Array<targetStation> = [...prev];
20+
newData.forEach((targetStation) => {
21+
const foundInstrument = targetStation.instruments.find(
22+
(instrument) => instrument.runstatePV === updatedPVName,
23+
);
24+
if (foundInstrument) foundInstrument.runstate = updatedPVvalue;
25+
});
26+
return newData;
27+
}
28+
29+
/**
30+
* Copy an original array then update an instrument's runstate PV, then subscribe to it. return the copied array.
31+
* @param prev the original array of target stations containing instrument runstate information
32+
* @param instListEntry the instrument to change
33+
* @param runstatePV the new runstate PV to update the array with and subscribe to
34+
* @param sendJsonMessage a callback to subscribe to the runstate PV
35+
*/
36+
export function updateInstrumentRunstatePV(
37+
prev: Array<targetStation>,
38+
instListEntry: instListEntry,
39+
runstatePV: string,
40+
sendJsonMessage: (a: IfcPVWSRequest) => void,
41+
) {
42+
const newData: Array<targetStation> = [...prev];
43+
// Iterate through instruments in the instlist, get the runstate PV and subscribe
44+
newData.forEach((targetStation) => {
45+
const foundInstrument = targetStation.instruments.find(
46+
(instrument) => instrument.name === instListEntry.name,
47+
);
48+
if (foundInstrument) {
49+
foundInstrument.runstatePV = instListEntry.pvPrefix + runstatePV;
50+
// Subscribe to the instrument's runstate PV
51+
sendJsonMessage({
52+
type: PVWSRequestType.subscribe,
53+
pvs: [foundInstrument.runstatePV],
54+
});
55+
}
56+
});
57+
return newData;
58+
}

0 commit comments

Comments
 (0)