@villedemontreal/scripting
Version:
Scripting core utilities
301 lines • 19.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/require-await */
/* eslint-disable no-console */
/* eslint-disable max-lines-per-function */
const chai_1 = require("chai");
const fs = require("fs-extra");
const mocha_1 = require("mocha");
const sinon = require("sinon");
const sonarTestUtils_1 = require("../../src/utils/sonarTestUtils");
const testingUtils_1 = require("../../src/utils/testingUtils");
const sonar_1 = require("./sonar");
const sonarInit_1 = require("./sonarInit");
const nock = require('nock');
const chai = require('chai');
chai.should();
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
chai.use(require('chai-string'));
const sandbox = sinon.createSandbox();
let shellCommand;
let subScript;
// eslint-disable-next-line @typescript-eslint/ban-types
function getSonarScript(targetBranch, logger) {
let options = {};
if (targetBranch) {
options = {
targetBranch,
};
}
return new sonar_1.SonarScript({
args: {},
options,
program: sinon.stub(),
command: sinon.stub(),
ddash: sinon.stub(),
logger: logger,
});
}
function simulateCurrentGitLocalBranchIs(currentLocalBranch) {
shellCommand.withArgs('git', ['branch', '--show-current'], sinon.match.any).callThrough();
const mockSpawn = require('mock-spawn');
const mySpawn = mockSpawn();
require('child_process').spawn = mySpawn;
mySpawn.setDefault(mySpawn.simple(0 /* exit code */, currentLocalBranch /* stdout */));
}
function simulateThereIsNoLocalGitRepository() {
shellCommand.withArgs('git', ['branch', '--show-current'], sinon.match.any).callThrough();
const mockSpawn = require('mock-spawn');
const mySpawn = mockSpawn();
require('child_process').spawn = mySpawn;
const gitOutputMessage = 'fatal: not a git repository (or any of the parent directories): .git';
mySpawn.setDefault(mySpawn.simple(128 /* exit code */, gitOutputMessage /* stdout */));
}
const validPropertyFiles = [
'./src/utils/test-sonar-project_url-with-trailing-slash.properties',
'./src/utils/test-sonar-project_url-without-trailing-slash.properties',
];
(0, mocha_1.describe)('sonar script', function () {
(0, testingUtils_1.timeout)(this, 30000);
before(() => {
(0, testingUtils_1.setTestingConfigs)();
// @ts-ignore
shellCommand = sandbox.stub(sonar_1.SonarScript.prototype, 'invokeShellCommand');
// @ts-ignore
subScript = sandbox.stub(sonar_1.SonarScript.prototype, 'invokeScript');
});
afterEach(() => {
sandbox.resetHistory();
sandbox.resetBehavior();
nock.cleanAll();
});
after(() => {
sandbox.restore();
});
(0, mocha_1.it)(` should fail when sonar-project.properties is missing`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, "ENOENT: no such file or directory, open 'sonar-project.properties'");
(0, chai_1.expect)(loggerRecorder.recordedLogs).to.equal(`info: Script "sonar" starting...
error: Script "sonar" failed after 0 s with: ENOENT: no such file or directory, open 'sonar-project.properties'
`);
});
validPropertyFiles.forEach((propertyFile) => {
(0, mocha_1.describe)(` when using "${propertyFile}" valid file`, async () => {
before(async () => {
await fs.copyFile(propertyFile, './sonar-project.properties');
});
after(async () => {
await fs.unlink('./sonar-project.properties');
});
(0, mocha_1.it)(` should fail when there is no local git repository`, async () => {
simulateThereIsNoLocalGitRepository();
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, 'Expected success codes were "0", but the process exited with "128".');
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith(`info: Script "sonar" starting...\n`)
.and.to.contain('info: Executing: git branch,--show-current\n')
.and.to.endWith('error: Script "sonar" failed after 0 s with: Expected success codes were "0", but the process exited with "128".\n');
subScript.should.not.have.been.called;
shellCommand.should.have.been.calledOnceWith('git', ['branch', '--show-current']);
});
(0, mocha_1.it)(` should fail when sonar server is not found.`, async () => {
simulateCurrentGitLocalBranchIs('current-local-branch');
(0, sonarTestUtils_1.simulateSonarServerIsNotFound)();
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarInitScript = getSonarScript(null, loggerRecorder.logger);
await (0, chai_1.expect)(sonarInitScript.run()).to.be.rejectedWith(Error, 'Not Found');
chai_1.assert.isTrue(nock.isDone(), `There are remaining expected HTTP calls: ${nock.pendingMocks().toString()}`);
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain.oneOf([
'error: "https://example.com/sonar/" Sonar server is not reachable.\n',
'error: "https://example.com/sonar" Sonar server is not reachable.\n',
])
.and.to.endWith('error: Script "sonar" failed after 0 s with: Not Found\n');
(0, chai_1.expect)(loggerRecorder.recordedLogs).to.not.contain('warn');
shellCommand.should.have.been.calledOnceWith('git', ['branch', '--show-current']);
});
(0, mocha_1.describe)(' when project already exists in Sonar', () => {
beforeEach(() => {
(0, sonarTestUtils_1.simulateSonarProjectAlreadyExists)();
simulateCurrentGitLocalBranchIs('current-local-branch');
});
(0, mocha_1.it)(` should succeed when simple code analysis succeeds.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
shellCommand.withArgs(sonar_1.SONAR_SCANNER).returns(0);
await sonarScript.run();
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith('info: Script "sonar" successful after 0 s\n');
subScript.should.not.have.been.called;
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
]);
});
(0, mocha_1.it)(` should succeed when code analysis against a target branch succeeds.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript('develop', loggerRecorder.logger);
shellCommand.withArgs(sonar_1.SONAR_SCANNER).returns(0);
await sonarScript.run();
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith('info: Script "sonar" successful after 0 s\n');
subScript.should.not.have.been.called;
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
'-Dsonar.branch.target=develop',
]);
});
(0, mocha_1.it)(` should fail when simple code analysis fails.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
shellCommand
.withArgs(sonar_1.SONAR_SCANNER)
.rejects(new Error('An error occurred while analyzing source code.'));
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, 'An error occurred while analyzing source code.');
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith(`error: Script "sonar" failed after 0 s with: An error occurred while analyzing source code.\n`);
subScript.should.not.have.been.called;
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
]);
});
});
(0, mocha_1.describe)(' when project does not yet exist in Sonar', () => {
beforeEach(() => {
(0, sonarTestUtils_1.simulateSonarProjectDoesNotYetExist)();
simulateCurrentGitLocalBranchIs('current-local-branch');
});
(0, mocha_1.it)(` should initialize Sonar project with a warning and then successfully analyze code.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
shellCommand.withArgs(sonar_1.SONAR_SCANNER).returns(0);
await sonarScript.run();
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain.oneOf([
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar/ ! Initializing it first...\n",
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar ! Initializing it first...\n",
])
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith('info: Script "sonar" successful after 0 s\n');
subScript.should.have.been.calledOnceWithExactly(sonarInit_1.SonarInitScript, {}, {});
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
]);
});
(0, mocha_1.it)(` should initialize Sonar project with a warning and then successfully analyze code against a target branch.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript('develop', loggerRecorder.logger);
shellCommand.withArgs(sonar_1.SONAR_SCANNER).returns(0);
await sonarScript.run();
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain.oneOf([
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar/ ! Initializing it first...\n",
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar ! Initializing it first...\n",
])
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith('info: Script "sonar" successful after 0 s\n');
subScript.should.have.been.calledOnceWithExactly(sonarInit_1.SonarInitScript, {}, {});
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
'-Dsonar.branch.target=develop',
]);
});
(0, mocha_1.it)(` should fail when Sonar project initialization fails.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
subScript
.withArgs(sonarInit_1.SonarInitScript)
.rejects(new Error('An error occurred while calling sonar-init sub-script.'));
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, 'An error occurred while calling sonar-init sub-script.');
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain.oneOf([
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar/ ! Initializing it first...\n",
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar ! Initializing it first...\n",
])
.and.to.endWith('error: Script "sonar" failed after 0 s with: An error occurred while calling sonar-init sub-script.\n')
.and.to.not.contain('info: Analyzing current branch "current-local-branch" source code...\n');
subScript.should.have.been.calledOnceWithExactly(sonarInit_1.SonarInitScript, {}, {});
shellCommand.should.have.been.calledOnceWith('git', ['branch', '--show-current']);
});
(0, mocha_1.it)(` should fail when code analysis fails after project initialization.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
subScript.withArgs(sonarInit_1.SonarInitScript).returns(0);
shellCommand
.withArgs(sonar_1.SONAR_SCANNER)
.rejects(new Error('An error occurred while analyzing source code.'));
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, 'An error occurred while analyzing source code.');
(0, chai_1.expect)(loggerRecorder.recordedLogs)
.to.startWith('info: Script "sonar" starting...\n')
.and.to.contain.oneOf([
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar/ ! Initializing it first...\n",
"warn: 'my-test-project-key' Sonar project does not yet exist on https://example.com/sonar ! Initializing it first...\n",
])
.and.to.contain('info: Analyzing current branch "current-local-branch" source code...\n')
.and.to.endWith('error: Script "sonar" failed after 0 s with: An error occurred while analyzing source code.\n');
subScript.should.have.been.calledOnceWithExactly(sonarInit_1.SonarInitScript, {}, {});
shellCommand.should.have.been.calledTwice;
shellCommand.should.have.been.calledWith('git', ['branch', '--show-current']);
shellCommand.should.have.been.calledWithExactly(sonar_1.SONAR_SCANNER, [
'-Dsonar.branch.name=current-local-branch',
]);
});
});
});
});
(0, mocha_1.describe)(' when using a sonar-project.properties file where Sonar host is missing', async () => {
before(async () => {
await fs.copyFile('./src/utils/test-sonar-project_missing-host.properties', './sonar-project.properties');
});
after(async () => {
await fs.unlink('./sonar-project.properties');
});
(0, mocha_1.it)(` should fail with a message about missing host url.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, '"sonar.host.url" property must be defined in "sonar-project.properties" file!');
subScript.should.not.have.been.called;
shellCommand.should.not.have.been.called;
});
});
(0, mocha_1.describe)(' when using a sonar-project.properties file where Sonar project key is missing', async () => {
before(async () => {
await fs.copyFile('./src/utils/test-sonar-project_missing-project-key.properties', './sonar-project.properties');
});
after(async () => {
await fs.unlink('./sonar-project.properties');
});
(0, mocha_1.it)(` should fail with a message about missing project key.`, async () => {
const loggerRecorder = new sonarTestUtils_1.LoggerRecorder();
const sonarScript = getSonarScript(null, loggerRecorder.logger);
await (0, chai_1.expect)(sonarScript.run()).to.be.rejectedWith(Error, '"sonar.projectKey" property must be defined in "sonar-project.properties" file!');
subScript.should.not.have.been.called;
shellCommand.should.not.have.been.called;
});
});
});
//# sourceMappingURL=sonar.test.js.map