diff --git a/src/cost-calculator.js b/src/cost-calculator.js index ad8f3c9..f4e3cec 100644 --- a/src/cost-calculator.js +++ b/src/cost-calculator.js @@ -1,26 +1,33 @@ 'use strict'; -const fs = require('fs'); +const fs = require('fs').promises; const path = require('path'); /** * Load rate configuration from rates.json. * - * @returns {Object} rate configuration + * @returns {Promise} rate configuration */ -function loadRatesConfig() { +async function loadRatesConfig() { const cfgPath = path.join(__dirname, 'rates.json'); try { - const data = fs.readFileSync(cfgPath, 'utf8'); + const data = await fs.readFile(cfgPath, 'utf8'); return JSON.parse(data); } catch (e) { if (e.code === 'ENOENT') { return {}; } if (e instanceof SyntaxError) { - console.error(`Invalid JSON in rate configuration: ${e.message}`); + console.error('Invalid JSON in rate configuration', { + path: cfgPath, + error: e.message, + }); } else { - console.error(`Error loading rate configuration: ${e.message}`); + console.error('Error loading rate configuration', { + path: cfgPath, + error: e.message, + code: e.code, + }); } throw e; } diff --git a/test/unit/calculator.test.js b/test/unit/calculator.test.js index 2f308da..e277637 100644 --- a/test/unit/calculator.test.js +++ b/test/unit/calculator.test.js @@ -3,14 +3,14 @@ const fs = require('fs'); const path = require('path'); const { calculateCharges, loadRatesConfig } = require('../../src/cost-calculator'); -function testFileConfig() { +async function testFileConfig() { const usage = [ { account: 'education', date: '2024-01-15', core_hours: 100, gpu_hours: 10 }, { account: 'research', date: '2024-02-01', core_hours: 50, gpu_hours: 5 }, { account: 'special', date: '2024-02-01', core_hours: 100, gpu_hours: 20 }, { account: 'other', date: '2024-02-01', core_hours: 10 } ]; - const config = loadRatesConfig(); + const config = await loadRatesConfig(); const charges = calculateCharges(usage, config); assert.strictEqual(charges['2024-01'].education.cost, (100 * 0.015 + 10 * 0.15) * 0.5); assert.strictEqual(charges['2024-02'].research.cost, 50 * 0.01 + 5 * 0.1); @@ -42,24 +42,24 @@ function testInvalidUsageIgnored() { assert.deepStrictEqual(charges, {}); } -function testMissingConfig() { +async function testMissingConfig() { const cfgPath = path.join(__dirname, '../../src/rates.json'); const backup = cfgPath + '.bak'; fs.renameSync(cfgPath, backup); try { - const cfg = loadRatesConfig(); + const cfg = await loadRatesConfig(); assert.deepStrictEqual(cfg, {}); } finally { fs.renameSync(backup, cfgPath); } } -function testInvalidConfig() { +async function testInvalidConfig() { const cfgPath = path.join(__dirname, '../../src/rates.json'); const original = fs.readFileSync(cfgPath, 'utf8'); fs.writeFileSync(cfgPath, '{ invalid json', 'utf8'); try { - assert.throws(() => loadRatesConfig(), SyntaxError); + await assert.rejects(loadRatesConfig, SyntaxError); } finally { fs.writeFileSync(cfgPath, original, 'utf8'); } @@ -102,19 +102,22 @@ function testRoundingTotals() { assert.strictEqual(june.round.cost, 0.22); } -function run() { - testFileConfig(); +async function run() { + await testFileConfig(); testPassedConfig(); testInvalidUsageIgnored(); - testMissingConfig(); - testInvalidConfig(); + await testMissingConfig(); + await testInvalidConfig(); testNegativeInputs(); testRoundingTotals(); console.log('All calculator tests passed.'); } if (require.main === module) { - run(); + run().catch(err => { + console.error(err); + process.exit(1); + }); } module.exports = run;