Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 15 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@apidevtools/json-schema-ref-parser": "^14.0.2",
"ajv": "^8.17.1",
"axios": "^1.10.0",
"doc-detective-common": "^3.1.1",
"doc-detective-common": "^3.1.1-dev.2",
"dotenv": "^16.5.0",
"json-schema-faker": "^0.5.9",
"posthog-node": "^5.1.1",
Expand Down
21 changes: 21 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { log, loadEnvs, replaceEnvs } = require("./utils");
const { loadDescription } = require("./openapi");

exports.setConfig = setConfig;
exports.resolveConcurrentRunners = resolveConcurrentRunners;

/**
* Deep merge two objects, with override properties taking precedence
Expand Down Expand Up @@ -190,6 +191,22 @@ defaultFileTypes = {
html: defaultFileTypes.html_1_0,
};

/**
* Resolves the concurrentRunners configuration value from various input formats
* to a concrete integer for the core execution engine.
*
* @param {Object} config - The configuration object
* @returns {number} The resolved concurrent runners value
*/
function resolveConcurrentRunners(config) {
if (config.concurrentRunners === true) {
// Cap at 4 only for the boolean convenience option
return Math.min(os.cpus().length, 4);
}
// Respect explicit numeric values and default
return config.concurrentRunners || 1;
}

/**
* Sets up and validates the configuration object for Doc Detective
* @async
Expand Down Expand Up @@ -380,6 +397,10 @@ async function setConfig({ config }) {

// Detect current environment.
config.environment = getEnvironment();

// Resolve concurrent runners configuration
config.concurrentRunners = resolveConcurrentRunners(config);

// TODO: Revise loadDescriptions() so it doesn't mutate the input but instead returns an updated object
await loadDescriptions(config);

Expand Down
100 changes: 100 additions & 0 deletions src/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,103 @@ function deepObjectExpect(actual, expected) {
}
});
}

describe("resolveConcurrentRunners", function () {
const { resolveConcurrentRunners } = require("./config");
const os = require("os");
let originalCpus;

beforeEach(function () {
// Save original os.cpus function
originalCpus = os.cpus;
});

afterEach(function () {
// Restore original os.cpus function
os.cpus = originalCpus;
});

it("should resolve boolean true on 8-core system to 4", function () {
// Mock os.cpus().length = 8
os.cpus = sinon.stub().returns(new Array(8));

const result = resolveConcurrentRunners({ concurrentRunners: true });
expect(result).to.equal(4);
});

it("should resolve boolean true on 2-core system to 2", function () {
// Mock os.cpus().length = 2
os.cpus = sinon.stub().returns(new Array(2));

const result = resolveConcurrentRunners({ concurrentRunners: true });
expect(result).to.equal(2);
});

it("should resolve boolean true on 16-core system to 4", function () {
// Mock os.cpus().length = 16
os.cpus = sinon.stub().returns(new Array(16));

const result = resolveConcurrentRunners({ concurrentRunners: true });
expect(result).to.equal(4);
});

it("should resolve boolean true on 1-core system to 1", function () {
// Mock os.cpus().length = 1
os.cpus = sinon.stub().returns(new Array(1));

const result = resolveConcurrentRunners({ concurrentRunners: true });
expect(result).to.equal(1);
});

it("should resolve explicit integer 8 to 8", function () {
const result = resolveConcurrentRunners({ concurrentRunners: 8 });
expect(result).to.equal(8);
});

it("should resolve explicit integer 1 to 1", function () {
const result = resolveConcurrentRunners({ concurrentRunners: 1 });
expect(result).to.equal(1);
});

it("should resolve explicit integer 16 to 16", function () {
const result = resolveConcurrentRunners({ concurrentRunners: 16 });
expect(result).to.equal(16);
});

it("should resolve undefined to 1", function () {
const result = resolveConcurrentRunners({});
expect(result).to.equal(1);
});

it("should resolve null to 1", function () {
const result = resolveConcurrentRunners({ concurrentRunners: null });
expect(result).to.equal(1);
});

it("should resolve 0 to 1", function () {
const result = resolveConcurrentRunners({ concurrentRunners: 0 });
expect(result).to.equal(1);
});

it("should resolve boolean false to 1", function () {
const result = resolveConcurrentRunners({ concurrentRunners: false });
expect(result).to.equal(1);
});

it("should handle integration with setConfig function", async function () {
const inputConfig = {
input: ["test.md"],
concurrentRunners: true,
logLevel: "info",
fileTypes: ["markdown"]
};

// Mock CPU count to 8 cores
os.cpus = sinon.stub().returns(new Array(8));

const result = await setConfig({ config: inputConfig });

// Should resolve boolean true to 4 (capped) on 8-core system
expect(result.concurrentRunners).to.equal(4);
});
});