Emergency Stop
This commit is contained in:
@@ -32,6 +32,28 @@ function request(url) {
|
||||
});
|
||||
}
|
||||
|
||||
function post(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const agent = new https.Agent({ rejectUnauthorized: false });
|
||||
const parsed = new URL(url);
|
||||
const options = {
|
||||
hostname: parsed.hostname,
|
||||
port: parsed.port,
|
||||
path: parsed.pathname,
|
||||
method: 'POST',
|
||||
agent,
|
||||
headers: { 'Content-Length': 0 }
|
||||
};
|
||||
const req = https.request(options, res => {
|
||||
let data = '';
|
||||
res.on('data', c => { data += c.toString(); });
|
||||
res.on('end', () => resolve({ statusCode: res.statusCode, body: data }));
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
describe('InfoServer', () => {
|
||||
let server;
|
||||
let port;
|
||||
@@ -189,4 +211,152 @@ describe('InfoServer', () => {
|
||||
const { statusCode } = await request(`https://127.0.0.1:${port}/api/unknown`);
|
||||
expect(statusCode).toBe(404);
|
||||
});
|
||||
|
||||
// ── Emergency Stop Endpoints ─────────────────────────────────────────────
|
||||
|
||||
test('POST /api/emergency-stop ruft emergencyStop() auf allen Sendern auf', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const stopA = jest.fn(() => Promise.resolve({ ok: true }));
|
||||
const stopB = jest.fn(() => Promise.resolve({ ok: true, skipped: true }));
|
||||
const senders = [
|
||||
{ name: 'Base', instance: { emergencyStop: stopA, alarmUnlock: jest.fn(() => Promise.resolve({ ok: true })) } },
|
||||
{ name: 'EmergencyStop', instance: { emergencyStop: stopB, alarmUnlock: jest.fn(() => Promise.resolve({ ok: true, skipped: true })) } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await post(`https://127.0.0.1:${port}/api/emergency-stop`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(true);
|
||||
expect(stopA).toHaveBeenCalledTimes(1);
|
||||
expect(stopB).toHaveBeenCalledTimes(1);
|
||||
expect(json.results).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('POST /api/alarm-unlock ruft alarmUnlock() auf allen Sendern auf', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const unlockA = jest.fn(() => Promise.resolve({ ok: true }));
|
||||
const unlockB = jest.fn(() => Promise.resolve({ ok: true, skipped: true }));
|
||||
const senders = [
|
||||
{ name: 'Base', instance: { emergencyStop: jest.fn(() => Promise.resolve({ ok: true })), alarmUnlock: unlockA } },
|
||||
{ name: 'EmergencyStop', instance: { emergencyStop: jest.fn(() => Promise.resolve({ ok: true })), alarmUnlock: unlockB } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await post(`https://127.0.0.1:${port}/api/alarm-unlock`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(true);
|
||||
expect(unlockA).toHaveBeenCalledTimes(1);
|
||||
expect(unlockB).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('POST /api/emergency-stop ok=false wenn ein Sender fehlschlägt', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const senders = [
|
||||
{ name: 'Base', instance: { emergencyStop: () => Promise.resolve({ ok: false, error: 'not connected' }), alarmUnlock: () => Promise.resolve({ ok: true }) } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await post(`https://127.0.0.1:${port}/api/emergency-stop`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(false);
|
||||
expect(json.results[0].ok).toBe(false);
|
||||
});
|
||||
|
||||
test('GET /api/power-status gibt armed=true zurück wenn Shelly output:true', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const getArmedFn = jest.fn(() => Promise.resolve({ ok: true, armed: true, voltage: 234.9, power: 15.5 }));
|
||||
const senders = [
|
||||
{ name: 'EmergencyStop', instance: { emergencyStop: () => Promise.resolve({ ok: true }), alarmUnlock: () => Promise.resolve({ ok: true }), getArmed: getArmedFn } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await request(`https://127.0.0.1:${port}/api/power-status`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(true);
|
||||
expect(json.armed).toBe(true);
|
||||
expect(getArmedFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('GET /api/power-status gibt armed=false zurück wenn kein Shelly konfiguriert', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const senders = [
|
||||
{ name: 'Base', instance: { emergencyStop: () => Promise.resolve({ ok: true }), alarmUnlock: () => Promise.resolve({ ok: true }) } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await request(`https://127.0.0.1:${port}/api/power-status`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(false);
|
||||
expect(json.armed).toBe(false);
|
||||
expect(json.error).toMatch(/no shelly/);
|
||||
});
|
||||
|
||||
test('POST /api/power-on ruft powerOn() auf Shelly-Sender auf', async () => {
|
||||
const key = fs.readFileSync('https/localhost.key');
|
||||
const cert = fs.readFileSync('https/localhost.pem');
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 0, y: 0, z: 0, phi: 0, theta: 0, psi: 0, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
|
||||
const powerOnFn = jest.fn(() => Promise.resolve({ ok: true, status: 200 }));
|
||||
const senders = [
|
||||
{ name: 'Base', instance: { emergencyStop: () => Promise.resolve({ ok: true }), alarmUnlock: () => Promise.resolve({ ok: true }) } },
|
||||
{ name: 'EmergencyStop', instance: { emergencyStop: () => Promise.resolve({ ok: true }), alarmUnlock: () => Promise.resolve({ ok: true }), powerOn: powerOnFn } }
|
||||
];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
port = await listen(server);
|
||||
|
||||
const { statusCode, body } = await post(`https://127.0.0.1:${port}/api/power-on`);
|
||||
expect(statusCode).toBe(200);
|
||||
const json = JSON.parse(body);
|
||||
expect(json.ok).toBe(true);
|
||||
expect(powerOnFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user