Skip to content

Commit

Permalink
refactor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RahulGautamSingh committed Dec 30, 2024
1 parent 6e15fdc commit aa586b3
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 252 deletions.
222 changes: 11 additions & 211 deletions lib/workers/repository/reconfigure/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,242 +1,42 @@
import { mock } from 'jest-mock-extended';
import type { RenovateConfig } from '../../../../test/util';
import { fs, git, mocked, partial, platform, scm } from '../../../../test/util';
import { logger, mocked, scm } from '../../../../test/util';
import { GlobalConfig } from '../../../config/global';
import { logger } from '../../../logger';
import type { Pr } from '../../../modules/platform/types';
import * as _cache from '../../../util/cache/repository';
import type { LongCommitSha } from '../../../util/git/types';
import * as _merge from '../init/merge';
import * as _validate from './validate';
import { checkReconfigureBranch } from '.';

jest.mock('../../../util/cache/repository');
jest.mock('../../../util/fs');
jest.mock('../../../util/git');
jest.mock('../init/merge');
jest.mock('./validate');

const cache = mocked(_cache);
const merge = mocked(_merge);
const validate = mocked(_validate);

describe('workers/repository/reconfigure/index', () => {
const config: RenovateConfig = {
branchPrefix: 'prefix/',
baseBranch: 'base',
statusCheckNames: partial<RenovateConfig['statusCheckNames']>({
configValidation: 'renovate/config-validation',
}),
};

beforeEach(() => {
config.repository = 'some/repo';
merge.detectConfigFile.mockResolvedValue('renovate.json');
scm.branchExists.mockResolvedValue(true);
cache.getCache.mockReturnValue({});
git.getBranchCommit.mockReturnValue('sha' as LongCommitSha);
fs.readLocalFile.mockResolvedValue(null);
platform.getBranchStatusCheck.mockResolvedValue(null);
GlobalConfig.reset();
scm.branchExists.mockResolvedValue(true);
validate.validateReconfigureBranch.mockResolvedValue(undefined);
});

it('no effect when running with platform=local', async () => {
GlobalConfig.set({ platform: 'local' });
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith(
expect(logger.logger.debug).toHaveBeenCalledWith(
'Not attempting to reconfigure when running with local platform',
);
});

it('no effect on repo with no reconfigure branch', async () => {
scm.branchExists.mockResolvedValueOnce(false);
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith('No reconfigure branch found');
});

it('logs error if config file search fails', async () => {
const err = new Error();
merge.detectConfigFile.mockRejectedValueOnce(err as never);
await checkReconfigureBranch(config);
expect(logger.error).toHaveBeenCalledWith(
{ err },
'Error while searching for config file in reconfigure branch',
);
});

it('throws error if config file not found in reconfigure branch', async () => {
merge.detectConfigFile.mockResolvedValue(null);
await checkReconfigureBranch(config);
expect(logger.warn).toHaveBeenCalledWith(
'No config file found in reconfigure branch',
);
});

it('logs error if config file is unreadable', async () => {
const err = new Error();
fs.readLocalFile.mockRejectedValueOnce(err as never);
await checkReconfigureBranch(config);
expect(logger.error).toHaveBeenCalledWith(
{ err },
'Error while reading config file',
);
});

it('throws error if config file is empty', async () => {
await checkReconfigureBranch(config);
expect(logger.warn).toHaveBeenCalledWith('Empty or invalid config file');
});

it('throws error if config file content is invalid', async () => {
fs.readLocalFile.mockResolvedValueOnce(`
{
"name":
}
`);
await checkReconfigureBranch(config);
expect(logger.error).toHaveBeenCalledWith(
{ err: expect.any(Object) },
'Error while parsing config file',
);
expect(platform.setBranchStatus).toHaveBeenCalledWith({
branchName: 'prefix/reconfigure',
context: 'renovate/config-validation',
description: 'Validation Failed - Unparsable config file',
state: 'red',
});
});

it('handles failed validation', async () => {
fs.readLocalFile.mockResolvedValueOnce(`
{
"enabledManagers": ["docker"]
}
`);
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith(
{ errors: expect.any(String) },
'Validation Errors',
expect(logger.logger.debug).toHaveBeenCalledWith(
'No reconfigure branch found',
);
expect(platform.setBranchStatus).toHaveBeenCalledWith({
branchName: 'prefix/reconfigure',
context: 'renovate/config-validation',
description: 'Validation Failed',
state: 'red',
});
});

it('adds comment if reconfigure PR exists', async () => {
fs.readLocalFile.mockResolvedValueOnce(`
{
"enabledManagers": ["docker"]
}
`);
platform.findPr.mockResolvedValueOnce(mock<Pr>({ number: 1 }));
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith(
{ errors: expect.any(String) },
'Validation Errors',
);
expect(platform.setBranchStatus).toHaveBeenCalled();
expect(platform.ensureComment).toHaveBeenCalled();
});

it('handles successful validation', async () => {
const pJson = `
{
"renovate": {
"enabledManagers": ["npm"]
}
}
`;
merge.detectConfigFile.mockResolvedValue('package.json');
fs.readLocalFile.mockResolvedValueOnce(pJson).mockResolvedValueOnce(pJson);
await checkReconfigureBranch(config);
expect(platform.setBranchStatus).toHaveBeenCalledWith({
branchName: 'prefix/reconfigure',
context: 'renovate/config-validation',
description: 'Validation Successful',
state: 'green',
});
});

it('skips adding status check if statusCheckNames.configValidation is null', async () => {
cache.getCache.mockReturnValueOnce({
reconfigureBranchCache: {
reconfigureBranchSha: 'new-sha',
isConfigValid: false,
},
});

await checkReconfigureBranch({
...config,
statusCheckNames: partial<RenovateConfig['statusCheckNames']>({
configValidation: null,
}),
});
expect(logger.debug).toHaveBeenCalledWith(
'Status check is null or an empty string, skipping status check addition.',
);
expect(platform.setBranchStatus).not.toHaveBeenCalled();
});

it('skips adding status check if statusCheckNames.configValidation is empty string', async () => {
cache.getCache.mockReturnValueOnce({
reconfigureBranchCache: {
reconfigureBranchSha: 'new-sha',
isConfigValid: false,
},
});

await checkReconfigureBranch({
...config,
statusCheckNames: partial<RenovateConfig['statusCheckNames']>({
configValidation: '',
}),
});
expect(logger.debug).toHaveBeenCalledWith(
'Status check is null or an empty string, skipping status check addition.',
);
expect(platform.setBranchStatus).not.toHaveBeenCalled();
});

it('skips validation if cache is valid', async () => {
cache.getCache.mockReturnValueOnce({
reconfigureBranchCache: {
reconfigureBranchSha: 'sha',
isConfigValid: false,
},
});
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith(
'Skipping validation check as branch sha is unchanged',
);
});

it('skips validation if status check present', async () => {
cache.getCache.mockReturnValueOnce({
reconfigureBranchCache: {
reconfigureBranchSha: 'new_sha',
isConfigValid: false,
},
});
platform.getBranchStatusCheck.mockResolvedValueOnce('green');
await checkReconfigureBranch(config);
expect(logger.debug).toHaveBeenCalledWith(
'Skipping validation check because status check already exists.',
);
});

it('handles non-default config file', async () => {
merge.detectConfigFile.mockResolvedValue('.renovaterc');
fs.readLocalFile.mockResolvedValueOnce(`
{
"enabledManagers": ["npm",]
}
`);
await checkReconfigureBranch(config);
expect(platform.setBranchStatus).toHaveBeenCalledWith({
branchName: 'prefix/reconfigure',
context: 'renovate/config-validation',
description: 'Validation Successful',
state: 'green',
});
it('validates reconfigure branch', async () => {
await expect(checkReconfigureBranch(config)).toResolve();
});
});
30 changes: 2 additions & 28 deletions lib/workers/repository/reconfigure/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { GlobalConfig } from '../../../config/global';
import type { RenovateConfig } from '../../../config/types';
import { logger } from '../../../logger';
import { platform } from '../../../modules/platform';
import { scm } from '../../../modules/platform/scm';
import { deleteReconfigureBranchCache } from './reconfigure-cache';
import { getReconfigureBranchName } from './utils';
Expand All @@ -25,7 +24,7 @@ export async function checkReconfigureBranch(
logger.debug('checkReconfigureBranch()');
if (GlobalConfig.get('platform') === 'local') {
logger.debug(
'Not attempting to check reconfigure branch when running with local platform',
'Not attempting to reconfigure when running with local platform',
);
return;
}
Expand All @@ -40,30 +39,5 @@ export async function checkReconfigureBranch(
return;
}

// check for the pr if it exists before hand so we do not need to make 2 calls
const reconfigurePr = await platform.findPr({
branchName: reconfigureBranch,
state: 'open',
includeOtherAuthors: true,
});
const { status } = await validateReconfigureBranch(config, reconfigurePr);

// config is invalid someway
if (!status) {
logger.debug('Config is invalid skipping Pr creation');
}

// if status is true it mean 4 things
// 1. config file present
// 2. it has a valid config file name
// 3. it has valid json in its
// 4. the config in it is valid

// now we need to check if a pr is present or not
// and if it is then, see if we can update anything in it.
// first test how an onboarding pr looks like and the info in it
// can be done by test run a repo or we can check the code
// remaining query is whether: the vaidate reconfigure branch needs to be refactored further?
// how the cache will be handled
// what happens if sha is same? > nothing cause we do not lookup so no sha change do nothing: unless a or is missing do created that
await validateReconfigureBranch(config);
}
Loading

0 comments on commit aa586b3

Please sign in to comment.