mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
feat: constraints limit in a strategy (#7554)
This commit is contained in:
parent
ef80d7f81e
commit
7ca2ace0bc
@ -200,6 +200,7 @@ exports[`should create default config 1`] = `
|
|||||||
"actionSetsPerProject": 5,
|
"actionSetsPerProject": 5,
|
||||||
"apiTokens": 2000,
|
"apiTokens": 2000,
|
||||||
"constraintValues": 250,
|
"constraintValues": 250,
|
||||||
|
"constraints": 30,
|
||||||
"environments": 50,
|
"environments": 50,
|
||||||
"featureEnvironmentStrategies": 30,
|
"featureEnvironmentStrategies": 30,
|
||||||
"featureFlags": 5000,
|
"featureFlags": 5000,
|
||||||
|
@ -663,6 +663,10 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
options?.resourceLimits?.constraintValues || 250,
|
options?.resourceLimits?.constraintValues || 250,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
constraints: Math.max(
|
||||||
|
0,
|
||||||
|
parseEnvVarNumber(process.env.UNLEASH_CONSTRAINTS_LIMIT, 30),
|
||||||
|
),
|
||||||
environments: parseEnvVarNumber(
|
environments: parseEnvVarNumber(
|
||||||
process.env.UNLEASH_ENVIRONMENTS_LIMIT,
|
process.env.UNLEASH_ENVIRONMENTS_LIMIT,
|
||||||
50,
|
50,
|
||||||
|
@ -387,19 +387,24 @@ class FeatureToggleService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateConstraintValuesLimit(updatedConstrains: IConstraint[]) {
|
validateConstraintsLimit(updatedConstrains: IConstraint[]) {
|
||||||
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
||||||
|
|
||||||
const limit = this.resourceLimits.constraintValues;
|
const constraintsLimit = this.resourceLimits.constraints;
|
||||||
|
if (updatedConstrains.length > constraintsLimit) {
|
||||||
|
throw new ExceedsLimitError(`constraints`, constraintsLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
const constraintValuesLimit = this.resourceLimits.constraintValues;
|
||||||
const constraintOverLimit = updatedConstrains.find(
|
const constraintOverLimit = updatedConstrains.find(
|
||||||
(constraint) =>
|
(constraint) =>
|
||||||
Array.isArray(constraint.values) &&
|
Array.isArray(constraint.values) &&
|
||||||
constraint.values?.length > limit,
|
constraint.values?.length > constraintValuesLimit,
|
||||||
);
|
);
|
||||||
if (constraintOverLimit) {
|
if (constraintOverLimit) {
|
||||||
throw new ExceedsLimitError(
|
throw new ExceedsLimitError(
|
||||||
`content values for ${constraintOverLimit.contextName}`,
|
`content values for ${constraintOverLimit.contextName}`,
|
||||||
limit,
|
constraintValuesLimit,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -649,7 +654,7 @@ class FeatureToggleService {
|
|||||||
strategyConfig.constraints &&
|
strategyConfig.constraints &&
|
||||||
strategyConfig.constraints.length > 0
|
strategyConfig.constraints.length > 0
|
||||||
) {
|
) {
|
||||||
this.validateConstraintValuesLimit(strategyConfig.constraints);
|
this.validateConstraintsLimit(strategyConfig.constraints);
|
||||||
strategyConfig.constraints = await this.validateConstraints(
|
strategyConfig.constraints = await this.validateConstraints(
|
||||||
strategyConfig.constraints,
|
strategyConfig.constraints,
|
||||||
);
|
);
|
||||||
@ -808,7 +813,7 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
if (existingStrategy.id === id) {
|
if (existingStrategy.id === id) {
|
||||||
if (updates.constraints && updates.constraints.length > 0) {
|
if (updates.constraints && updates.constraints.length > 0) {
|
||||||
this.validateConstraintValuesLimit(updates.constraints);
|
this.validateConstraintsLimit(updates.constraints);
|
||||||
updates.constraints = await this.validateConstraints(
|
updates.constraints = await this.validateConstraints(
|
||||||
updates.constraints,
|
updates.constraints,
|
||||||
);
|
);
|
||||||
|
@ -47,6 +47,50 @@ describe('Strategy limits', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should not allow to exceed constraints limit', async () => {
|
||||||
|
const LIMIT = 1;
|
||||||
|
const { featureToggleService, featureToggleStore } =
|
||||||
|
createFakeFeatureToggleService({
|
||||||
|
getLogger,
|
||||||
|
flagResolver: alwaysOnFlagResolver,
|
||||||
|
resourceLimits: {
|
||||||
|
constraints: LIMIT,
|
||||||
|
},
|
||||||
|
} as unknown as IUnleashConfig);
|
||||||
|
|
||||||
|
const addStrategy = (constraints: IConstraint[]) =>
|
||||||
|
featureToggleService.unprotectedCreateStrategy(
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
featureName: 'feature',
|
||||||
|
constraints: constraints,
|
||||||
|
} as IStrategyConfig,
|
||||||
|
{ projectId: 'default', featureName: 'feature' } as any,
|
||||||
|
{} as IAuditUser,
|
||||||
|
);
|
||||||
|
await featureToggleStore.create('default', {
|
||||||
|
name: 'feature',
|
||||||
|
createdByUserId: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
addStrategy([
|
||||||
|
{
|
||||||
|
values: ['1'],
|
||||||
|
operator: 'IN',
|
||||||
|
contextName: 'accountId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
values: ['2'],
|
||||||
|
operator: 'IN',
|
||||||
|
contextName: 'accountId',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
).rejects.toThrow(
|
||||||
|
"Failed to create constraints. You can't create more than the established limit of 1",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test('Should not allow to exceed constraint values limit', async () => {
|
test('Should not allow to exceed constraint values limit', async () => {
|
||||||
const LIMIT = 3;
|
const LIMIT = 3;
|
||||||
const { featureToggleService, featureToggleStore } =
|
const { featureToggleService, featureToggleStore } =
|
||||||
|
@ -20,6 +20,7 @@ export const resourceLimitsSchema = {
|
|||||||
'apiTokens',
|
'apiTokens',
|
||||||
'segments',
|
'segments',
|
||||||
'featureFlags',
|
'featureFlags',
|
||||||
|
'constraints',
|
||||||
],
|
],
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
properties: {
|
properties: {
|
||||||
@ -80,6 +81,12 @@ export const resourceLimitsSchema = {
|
|||||||
description:
|
description:
|
||||||
'The maximum number of values for a single constraint.',
|
'The maximum number of values for a single constraint.',
|
||||||
},
|
},
|
||||||
|
constraints: {
|
||||||
|
type: 'integer',
|
||||||
|
example: 30,
|
||||||
|
description:
|
||||||
|
'The maximum number of constraints in a single strategy.',
|
||||||
|
},
|
||||||
environments: {
|
environments: {
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
minimum: 1,
|
minimum: 1,
|
||||||
|
Loading…
Reference in New Issue
Block a user