Skip to content

Commit d4a33fd

Browse files
authored
Merge pull request #31 from doc-detective/copilot/fix-30
Add Concurrent Runners Resolution Logic
2 parents fc1b87c + 9251aac commit d4a33fd

File tree

4 files changed

+137
-23
lines changed

4 files changed

+137
-23
lines changed

package-lock.json

Lines changed: 15 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"@apidevtools/json-schema-ref-parser": "^14.0.2",
2828
"ajv": "^8.17.1",
2929
"axios": "^1.10.0",
30-
"doc-detective-common": "^3.1.1",
30+
"doc-detective-common": "^3.1.1-dev.2",
3131
"dotenv": "^16.5.0",
3232
"json-schema-faker": "^0.5.9",
3333
"posthog-node": "^5.1.1",

src/config.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { log, loadEnvs, replaceEnvs } = require("./utils");
44
const { loadDescription } = require("./openapi");
55

66
exports.setConfig = setConfig;
7+
exports.resolveConcurrentRunners = resolveConcurrentRunners;
78

89
/**
910
* Deep merge two objects, with override properties taking precedence
@@ -190,6 +191,22 @@ defaultFileTypes = {
190191
html: defaultFileTypes.html_1_0,
191192
};
192193

194+
/**
195+
* Resolves the concurrentRunners configuration value from various input formats
196+
* to a concrete integer for the core execution engine.
197+
*
198+
* @param {Object} config - The configuration object
199+
* @returns {number} The resolved concurrent runners value
200+
*/
201+
function resolveConcurrentRunners(config) {
202+
if (config.concurrentRunners === true) {
203+
// Cap at 4 only for the boolean convenience option
204+
return Math.min(os.cpus().length, 4);
205+
}
206+
// Respect explicit numeric values and default
207+
return config.concurrentRunners || 1;
208+
}
209+
193210
/**
194211
* Sets up and validates the configuration object for Doc Detective
195212
* @async
@@ -380,6 +397,10 @@ async function setConfig({ config }) {
380397

381398
// Detect current environment.
382399
config.environment = getEnvironment();
400+
401+
// Resolve concurrent runners configuration
402+
config.concurrentRunners = resolveConcurrentRunners(config);
403+
383404
// TODO: Revise loadDescriptions() so it doesn't mutate the input but instead returns an updated object
384405
await loadDescriptions(config);
385406

src/config.test.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,103 @@ function deepObjectExpect(actual, expected) {
402402
}
403403
});
404404
}
405+
406+
describe("resolveConcurrentRunners", function () {
407+
const { resolveConcurrentRunners } = require("./config");
408+
const os = require("os");
409+
let originalCpus;
410+
411+
beforeEach(function () {
412+
// Save original os.cpus function
413+
originalCpus = os.cpus;
414+
});
415+
416+
afterEach(function () {
417+
// Restore original os.cpus function
418+
os.cpus = originalCpus;
419+
});
420+
421+
it("should resolve boolean true on 8-core system to 4", function () {
422+
// Mock os.cpus().length = 8
423+
os.cpus = sinon.stub().returns(new Array(8));
424+
425+
const result = resolveConcurrentRunners({ concurrentRunners: true });
426+
expect(result).to.equal(4);
427+
});
428+
429+
it("should resolve boolean true on 2-core system to 2", function () {
430+
// Mock os.cpus().length = 2
431+
os.cpus = sinon.stub().returns(new Array(2));
432+
433+
const result = resolveConcurrentRunners({ concurrentRunners: true });
434+
expect(result).to.equal(2);
435+
});
436+
437+
it("should resolve boolean true on 16-core system to 4", function () {
438+
// Mock os.cpus().length = 16
439+
os.cpus = sinon.stub().returns(new Array(16));
440+
441+
const result = resolveConcurrentRunners({ concurrentRunners: true });
442+
expect(result).to.equal(4);
443+
});
444+
445+
it("should resolve boolean true on 1-core system to 1", function () {
446+
// Mock os.cpus().length = 1
447+
os.cpus = sinon.stub().returns(new Array(1));
448+
449+
const result = resolveConcurrentRunners({ concurrentRunners: true });
450+
expect(result).to.equal(1);
451+
});
452+
453+
it("should resolve explicit integer 8 to 8", function () {
454+
const result = resolveConcurrentRunners({ concurrentRunners: 8 });
455+
expect(result).to.equal(8);
456+
});
457+
458+
it("should resolve explicit integer 1 to 1", function () {
459+
const result = resolveConcurrentRunners({ concurrentRunners: 1 });
460+
expect(result).to.equal(1);
461+
});
462+
463+
it("should resolve explicit integer 16 to 16", function () {
464+
const result = resolveConcurrentRunners({ concurrentRunners: 16 });
465+
expect(result).to.equal(16);
466+
});
467+
468+
it("should resolve undefined to 1", function () {
469+
const result = resolveConcurrentRunners({});
470+
expect(result).to.equal(1);
471+
});
472+
473+
it("should resolve null to 1", function () {
474+
const result = resolveConcurrentRunners({ concurrentRunners: null });
475+
expect(result).to.equal(1);
476+
});
477+
478+
it("should resolve 0 to 1", function () {
479+
const result = resolveConcurrentRunners({ concurrentRunners: 0 });
480+
expect(result).to.equal(1);
481+
});
482+
483+
it("should resolve boolean false to 1", function () {
484+
const result = resolveConcurrentRunners({ concurrentRunners: false });
485+
expect(result).to.equal(1);
486+
});
487+
488+
it("should handle integration with setConfig function", async function () {
489+
const inputConfig = {
490+
input: ["test.md"],
491+
concurrentRunners: true,
492+
logLevel: "info",
493+
fileTypes: ["markdown"]
494+
};
495+
496+
// Mock CPU count to 8 cores
497+
os.cpus = sinon.stub().returns(new Array(8));
498+
499+
const result = await setConfig({ config: inputConfig });
500+
501+
// Should resolve boolean true to 4 (capped) on 8-core system
502+
expect(result.concurrentRunners).to.equal(4);
503+
});
504+
});

0 commit comments

Comments
 (0)