Files
trezor-suite/scripts/ci/connect-test-matrix-generator.js
2026-02-24 06:27:58 -07:00

240 lines
6.3 KiB
JavaScript

const DEBUG = false;
const log = (...args) => {
if (DEBUG) {
return console.log(...args);
}
};
const groups = {
api: {
name: 'api',
pattern:
'authorizeCoinjoin cancelCoinjoinAuthorization passphrase unlockPath setBusy authenticateDevice keepSession cancel.test info.test resetDevice',
includeFilter: '',
},
// temporarily created group for flaky test - to spend less time on reruns and to make test result in CI more readable without investigating long logs
apiFlaky: {
name: 'api-flaky',
pattern: 'init',
},
thp: {
name: 'thp',
pattern: 'thpPairing',
includeFilter: '',
},
management: {
name: 'management',
pattern: 'methods',
includeFilter:
'applySettings,applyFlags,getFeatures,getFirmwareHash,changeLanguage,loadDevice,telemetryGet',
},
btcSign: {
name: 'btc-sign',
pattern: 'methods',
includeFilter: 'signTransaction',
},
btcOthers: {
name: 'btc-others',
pattern: 'methods',
includeFilter:
'getAccountInfo,getAccountDescriptor,getAddress,getPublicKey,signMessage,verifyMessage,composeTransaction,getOwnershipId,getOwnershipProof',
},
stellar: {
name: 'stellar',
pattern: 'methods',
includeFilter: 'stellarGetAddress,stellarSignTransaction',
},
cardano: {
name: 'cardano',
pattern: 'methods',
includeFilter:
'cardanoGetAddress,cardanoGetNativeScriptHash,cardanoGetPublicKey,cardanoSignTransaction,cardanoSignMessage',
},
ethereum: {
name: 'ethereum',
pattern: 'methods',
includeFilter:
'ethereumGetAddress,ethereumGetPublicKey,ethereumSignMessage,ethereumSignTransaction,ethereumVerifyMessage,ethereumSignTypedData',
},
monero: {
name: 'monero',
pattern: 'methods',
includeFilter:
'moneroGetAddress,moneroGetWatchKey,moneroKeyImageSync,moneroSignTransaction',
},
ripple: {
name: 'ripple',
pattern: 'methods',
includeFilter: 'rippleGetAddress,rippleSignTransaction',
},
tezos: {
name: 'tezos',
pattern: 'methods',
includeFilter: 'tezosGetAddress,tezosGetPublicKey,tezosSignTransaction',
},
tron: {
name: 'tron',
pattern: 'methods',
includeFilter: 'tronGetAddress,tronSignTransaction',
},
solana: {
name: 'solana',
pattern: 'methods',
includeFilter:
'solanaGetAddress,solanaGetPublicKey,solanaSignTransaction,solanaComposeTransaction',
},
};
const firmwares1 = ['1.9.0', '1-latest', '1-main'];
const firmwares2 = ['2.3.0', '2-latest', '2-main'];
const inputs = [
{
key: 'model',
value: ['T1B1', 'T2T1', 'T2B1', 'T3B1', 'T3T1', 'T3W1'],
},
{
key: 'firmware',
value: ({ model }) => {
return model === 'T1B1' ? firmwares1 : firmwares2;
},
},
{
key: 'transport',
value: ['node-bridge', '2.0.33'],
},
{
key: 'groups',
value: ({ model, firmware }) => {
return Object.values(groups).filter(group => {
if (group.name === 'thp') {
return firmware !== '2.3.0' && model === 'T3W1';
}
return true;
});
},
},
{
key: 'env',
value: ['node', 'web'],
},
{
key: 'disable_cache_tx',
value: ['true', 'false'],
},
{
key: 'key',
value: [' '],
},
];
// Get command-line arguments, excluding 'node' and the script name
const args = process.argv.slice(2);
// Initialize an object to store the parsed arguments
const parsedArgs = {
key: ' ',
};
// Iterate over the arguments
args.forEach(arg => {
// Split each argument by '=' to separate the key and value
const [key, value] = arg.split('=');
// Remove the leading '--' from the key
const argName = key.replace(/^--/, '');
// Check if the value contains commas to create an array
parsedArgs[argName] = value.includes(',') ? value.split(',') : value;
});
log('parsedArgs', parsedArgs);
const validateArgs = () => {
const requiredArgs = ['model', 'firmware', 'env', 'groups', 'disable_cache_tx', 'transport'];
requiredArgs.forEach(arg => {
if (!parsedArgs[arg]) {
throw new Error(`Missing required argument: ${arg}`);
}
});
};
validateArgs();
log('validated args', parsedArgs);
/**
a method that takes inputs and creates all combinations of results like this:
{model: T1B1, firmware: 1.9.0, transport: 'Bridge'... }
{model: T1B1, firmware: 1.9.0, transport: 'NodeBridge'... }
{model: T1B1, firmware: 1-latest, transport: 'Bridge'... }
{model: T1B1, firmware: 1-latest, transport: 'NodeBridge'... }
*/
const createCartesian = inputs => {
const keys = inputs.map(m => m.key);
const values = inputs.map(m => m.value);
const results = [];
const create = (index, current) => {
if (index === keys.length) {
results.push(current);
return;
}
const key = keys[index];
const value = typeof values[index] === 'function' ? values[index](current) : values[index];
for (let i = 0; i < value.length; i++) {
create(index + 1, {
...current,
[key]: value[i],
});
}
};
create(0, {});
return results;
};
const cartesian = createCartesian(inputs);
log('cartesian length', cartesian.length);
/**
* filter cartesian by passed arguments
*/
const filterCartesianResultByArgs = () => {
const getValue = input => {
if (typeof input === 'object') {
return input.name;
}
return input;
};
return cartesian.filter(m => {
return Object.keys(m).every(key => {
const filterBy = parsedArgs[key];
if (filterBy === 'all') return true;
if (Array.isArray(filterBy)) {
return filterBy.includes(getValue(m[key]));
}
return getValue(m[key]) === filterBy;
});
});
};
const filtered = filterCartesianResultByArgs();
log('filtered.length', filtered.length);
if (!DEBUG) {
process.stdout.write(
JSON.stringify({
include: filtered,
}),
);
}