Skip to content
Open
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
40 changes: 33 additions & 7 deletions src/core/permsets/PermissionSetGroupUpdateAwaiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@
import QueryHelper from '../queryHelper/QueryHelper';
import { delay } from '../utils/Delay';

const psGroupQuery = `SELECT Id,MasterLabel,Status FROM PermissionSetGroup WHERE Status IN ('Updating', 'Outdated')`;
const psGroupQuery = `SELECT Id,MasterLabel,Status FROM PermissionSetGroup WHERE Status = 'Updating'`;

export default class PermissionSetGroupUpdateAwaiter {
constructor(private connection: Connection, private logger: Logger, private intervalBetweenRepeats = 60000) {}
constructor(
private connection: Connection,

Check failure on line 10 in src/core/permsets/PermissionSetGroupUpdateAwaiter.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/core/permsets/PermissionSetGroupUpdateAwaiter.ts#L10

'connection' is defined but never used.
private logger: Logger,

Check failure on line 11 in src/core/permsets/PermissionSetGroupUpdateAwaiter.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/core/permsets/PermissionSetGroupUpdateAwaiter.ts#L11

'logger' is defined but never used.
private intervalBetweenRepeats = 30000

Check failure on line 12 in src/core/permsets/PermissionSetGroupUpdateAwaiter.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/core/permsets/PermissionSetGroupUpdateAwaiter.ts#L12

'intervalBetweenRepeats' is assigned a value but never used.
) {}

private getMaxWaitingTimeMilliseconds(): number {
const maxWaitingTimeInMinutes = process.env.PSG_AWAITER_TIMEOUT_MINUTES ?? undefined;
if (maxWaitingTimeInMinutes) {
const maxWaitingTimeInMinutesParsed = Number(maxWaitingTimeInMinutes);
if (isNaN(maxWaitingTimeInMinutesParsed) || maxWaitingTimeInMinutesParsed <= 0) {
SFPLogger.log(`PSG_AWAITER_TIMEOUT_MINUTES env variable must be a positive number [${maxWaitingTimeInMinutes}]`, LoggerLevel.ERROR, this.logger);

Check failure on line 20 in src/core/permsets/PermissionSetGroupUpdateAwaiter.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/core/permsets/PermissionSetGroupUpdateAwaiter.ts#L20

Unsafe call of an `error` type typed value.
}
return maxWaitingTimeInMinutesParsed * 60 * 1000; // Convert minutes to milliseconds
}
}

async waitTillAllPermissionSetGroupIsUpdated() {
SFPLogger.log(
`Checking status of permission sets group..`,
LoggerLevel.INFO,
this.logger
);
const maxWaitingTime = this.getMaxWaitingTimeMilliseconds();

SFPLogger.log(`Checking status of permission sets group..`, LoggerLevel.INFO, this.logger);

Check failure on line 29 in src/core/permsets/PermissionSetGroupUpdateAwaiter.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/core/permsets/PermissionSetGroupUpdateAwaiter.ts#L29

Unsafe call of an `error` type typed value.
let totalTimeWaited = 0;
while (true) {
try {
let records = await QueryHelper.query(psGroupQuery, this.connection, false);
Expand All @@ -29,6 +43,17 @@
this.logger
);
await delay(this.intervalBetweenRepeats);
totalTimeWaited += this.intervalBetweenRepeats;
if (maxWaitingTime && (totalTimeWaited > maxWaitingTime)) {
SFPLogger.log(
`Max waiting time of ${
maxWaitingTime / 1000
} seconds exceeded. Proceeding with deployment`,
LoggerLevel.WARN,
this.logger
);
break;
}
} else {
SFPLogger.log(
`Proceeding with deployment, as no PermissionSetGroups are being updated`,
Expand All @@ -44,3 +69,4 @@
}
}
}

156 changes: 152 additions & 4 deletions tests/core/permsets/PermissionSetGroupUpdateAwaiter.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
import { MockTestOrgData, TestContext } from '../../../node_modules/@salesforce/core/lib/testSetup';
import { AuthInfo, Connection, OrgConfigProperties } from '@salesforce/core';
import { ConsoleLogger } from '@flxbl-io/sfp-logger';
import { AnyJson } from '@salesforce/ts-types';
const $$ = new TestContext();
import PermissionSetGroupUpdateAwaiter from '../../../src/core/permsets/PermissionSetGroupUpdateAwaiter';
import { expect } from '@jest/globals';

describe('Await till permissionsets groups are updated', () => {
const noUpdatingPsgRecords: AnyJson = {
records: [],
};
const someUpdatingPsgRecords: AnyJson = {
records: [
{
attributes: {
type: 'PermissionSetGroup',
url: '/services/data/v64.0/sobjects/PermissionSetGroup/0PG250000008nhNGAQ',
},
Id: '0PG250000008nhNGAQ',
MasterLabel: 'PSG1',
Status: 'Updating',
},
{
attributes: {
type: 'PermissionSetGroup',
url: '/services/data/v64.0/sobjects/PermissionSetGroup/0PG250000008nnVGAQ',
},
Id: '0PG250000008nnVGAQ',
MasterLabel: 'PSG2',
Status: 'Updating',
},
],
};

jest.spyOn(require('../../../src/core/utils/Delay'), 'delay').mockImplementation(() => Promise.resolve());

it('should return if all permsets groups are updated', async () => {
const testData = new MockTestOrgData();

Expand All @@ -15,21 +44,140 @@ describe('Await till permissionsets groups are updated', () => {
contents: await testData.getConfig(),
});

let records: AnyJson = {
records: [],
$$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
return Promise.resolve(noUpdatingPsgRecords);
};

const connection: Connection = await Connection.create({
authInfo: await AuthInfo.create({ username: testData.username }),
});

let permissionSetGroupUpdateAwaiter: PermissionSetGroupUpdateAwaiter = new PermissionSetGroupUpdateAwaiter(
connection, new ConsoleLogger()
);
await expect(permissionSetGroupUpdateAwaiter.waitTillAllPermissionSetGroupIsUpdated()).resolves.toBeUndefined();
});

it('should return if all permsets groups are updated after waiting for some time', async () => {
const testData = new MockTestOrgData();

await $$.stubConfig({ [OrgConfigProperties.TARGET_ORG]: testData.username });
await $$.stubAuths(testData);
$$.setConfigStubContents('AuthInfoConfig', {
contents: await testData.getConfig(),
});

let tryCount = 0;
$$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
if (tryCount === 0) {
tryCount++;
return Promise.resolve(someUpdatingPsgRecords);
}
return Promise.resolve(noUpdatingPsgRecords);
};

const connection: Connection = await Connection.create({
authInfo: await AuthInfo.create({ username: testData.username }),
});

let permissionSetGroupUpdateAwaiter: PermissionSetGroupUpdateAwaiter = new PermissionSetGroupUpdateAwaiter(
connection,
new ConsoleLogger()
);
await expect(permissionSetGroupUpdateAwaiter.waitTillAllPermissionSetGroupIsUpdated()).resolves.toBeUndefined();
});

it('should keep trying until all permsets groups are updated if there is no maximum wait time', async () => {
const testData = new MockTestOrgData();

await $$.stubConfig({ [OrgConfigProperties.TARGET_ORG]: testData.username });
await $$.stubAuths(testData);
$$.setConfigStubContents('AuthInfoConfig', {
contents: await testData.getConfig(),
});

let tryCount = 0;
$$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
if (tryCount < 5) {
// 5th try
tryCount++;
return Promise.resolve(someUpdatingPsgRecords);
}
return Promise.resolve(noUpdatingPsgRecords);
};

const connection: Connection = await Connection.create({
authInfo: await AuthInfo.create({ username: testData.username }),
});

let permissionSetGroupUpdateAwaiter: PermissionSetGroupUpdateAwaiter = new PermissionSetGroupUpdateAwaiter(
connection,
new ConsoleLogger()
);
await expect(permissionSetGroupUpdateAwaiter.waitTillAllPermissionSetGroupIsUpdated()).resolves.toBeUndefined();
expect(tryCount).toBe(5);
});

it('should keep trying until until max wait time is reached', async () => {
const testData = new MockTestOrgData();

await $$.stubConfig({ [OrgConfigProperties.TARGET_ORG]: testData.username });
await $$.stubAuths(testData);
$$.setConfigStubContents('AuthInfoConfig', {
contents: await testData.getConfig(),
});

$$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
return Promise.resolve(records);
return Promise.resolve(someUpdatingPsgRecords);
};

const connection: Connection = await Connection.create({
authInfo: await AuthInfo.create({ username: testData.username }),
});

process.env.PSG_AWAITER_TIMEOUT_MINUTES = '0.25'; // 15 seconds
let permissionSetGroupUpdateAwaiter: PermissionSetGroupUpdateAwaiter = new PermissionSetGroupUpdateAwaiter(
connection,
null
new ConsoleLogger(),
100, // try every 100ms
);
await expect(permissionSetGroupUpdateAwaiter.waitTillAllPermissionSetGroupIsUpdated()).resolves.toBeUndefined();
});

it('should not reach maximum time if all permsets groups udpated', async () => {
const testData = new MockTestOrgData();

await $$.stubConfig({ [OrgConfigProperties.TARGET_ORG]: testData.username });
await $$.stubAuths(testData);
$$.setConfigStubContents('AuthInfoConfig', {
contents: await testData.getConfig(),
});

let tryCount = 0;
$$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
if (tryCount < 3) {
// 3rd try in 300ms
tryCount++;
return Promise.resolve(someUpdatingPsgRecords);
}
return Promise.resolve(noUpdatingPsgRecords);
};



const connection: Connection = await Connection.create({
authInfo: await AuthInfo.create({ username: testData.username }),
});

process.env.PSG_AWAITER_TIMEOUT_MINUTES = '0.5'; // 30 seconds
let permissionSetGroupUpdateAwaiter: PermissionSetGroupUpdateAwaiter = new PermissionSetGroupUpdateAwaiter(
connection,
new ConsoleLogger(),
100, // try every 100ms
);
await expect(permissionSetGroupUpdateAwaiter.waitTillAllPermissionSetGroupIsUpdated()).resolves.toBeUndefined();
expect(tryCount).toBe(3); // 4 tries in total, first and then waiting 3 times
});
});