add tests for bootloader protocol errors

This commit is contained in:
David Lechner
2020-05-26 21:20:08 -05:00
committed by David Lechner
parent 3e4ea382e5
commit 7a7eba407f
4 changed files with 109 additions and 7 deletions
+25 -2
View File
@@ -77,6 +77,20 @@ export enum ProtectionLevel {
Level2 = 0x02,
}
/**
* Protocol error. Thrown e.g. when there is a malformed message.
*/
export class ProtocolError extends Error {
/**
* Creates a new ProtocolError.
* @param message The error message
* @param data The bytecodes that caused the error
*/
constructor(message: string, public data: DataView) {
super(message);
}
}
/**
* Creates a new message to erase the flash memory.
*/
@@ -192,11 +206,20 @@ export function parseErrorResponse(msg: DataView): Command {
assert(msg.getUint8(0) === 5, 'unexpected length');
// Error responses are ordered differently compared to command responses.
if (msg.getUint8(2) !== ErrorBytecode) {
throw Error('expecting error');
throw new ProtocolError(
`expecting error bytecode 0x05 but got 0x${msg
.getUint8(2)
.toString(16)
.padStart(2, '0')}`,
msg,
);
}
if (msg.getUint8(4) !== ErrorCode.UnknownCommand) {
// "command not recognized" is only possible error code
throw Error('unexpected error code');
throw new ProtocolError(
`unknown error code: 0x${msg.getUint8(4).toString(16).padStart(2, '0')}`,
msg,
);
}
const command = msg.getUint8(3);
return command;
+74 -1
View File
@@ -7,6 +7,7 @@ import {
BootloaderRequestActionType,
checksumRequest,
checksumResponse,
didError,
didReceive,
didRequest,
didSend,
@@ -25,7 +26,13 @@ import {
stateRequest,
stateResponse,
} from '../actions/bootloader';
import { Command, HubType, ProtectionLevel, Result } from '../protocols/bootloader';
import {
Command,
HubType,
ProtectionLevel,
ProtocolError,
Result,
} from '../protocols/bootloader';
import { createCountFunc } from '../utils/iter';
import bootloader from './bootloader';
@@ -271,4 +278,70 @@ describe('message decoder', () => {
await task.toPromise();
expect(dispatched[0]).toEqual(expected);
});
test.each([
[
'bad error bytecode',
[
0x05, // length
0x00, // unused (hub id)
0x04, // **invalid message type**
0x77, // get flash state command
0x05, // command not recognized
],
didError(
new ProtocolError(
'expecting error bytecode 0x05 but got 0x04',
new DataView(new Uint8Array().buffer),
),
),
],
[
'unknown error code',
[
0x05, // length
0x00, // unused (hub id)
0x05, // flash loader error message
0x77, // get flash state command
0x04, // **invalid error code**
],
didError(
new ProtocolError(
'unknown error code: 0x04',
new DataView(new Uint8Array().buffer),
),
),
],
[
'unknown response',
[
0x00, // **bad command**
0x01, // **junk**
0x02, // **junk**
0x03, // **junk**
0x04, // **junk**
],
didError(
new ProtocolError(
'unknown bootloader response type: 0x00',
new DataView(new Uint8Array().buffer),
),
),
],
])('protocol error', async (_n, message, expected) => {
const response = new Uint8Array(message);
const channel = stdChannel();
const dispatched = new Array<Action>();
const task = runSaga(
{
channel,
dispatch: (action: Action) => dispatched.push(action),
},
bootloader,
);
channel.put(didReceive(new DataView(response.buffer)));
task.cancel();
await task.toPromise();
expect(dispatched[0]).toEqual(expected);
});
});
+9 -3
View File
@@ -42,6 +42,7 @@ import {
checksumRequest,
checksumResponse,
connect,
didError,
didRequest,
disconnectRequest,
eraseRequest,
@@ -65,6 +66,7 @@ import {
ErrorBytecode,
HubType,
MaxProgramFlashSize,
ProtocolError,
createDisconnectRequest,
createEraseFlashRequest,
createGetChecksumRequest,
@@ -184,11 +186,15 @@ function* decodeResponse(action: BootloaderConnectionDidReceiveAction): Generato
yield put(errorResponse(parseErrorResponse(action.data)));
break;
default:
throw new Error(`Unknown bootloader response action ${action}`);
throw new ProtocolError(
`unknown bootloader response type: 0x${responseType
.toString(16)
.padStart(2, '0')}`,
action.data,
);
}
} catch (err) {
// TODO: dispatch an error action
console.error(`Error decoding message: ${err}`);
yield put(didError(err));
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2018",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,