1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-04 13:48:56 +02:00

feat: add tests for number validator

This commit is contained in:
Fredrik Oseberg 2022-02-24 14:21:28 +01:00
parent 371ad6c009
commit 6c8a228d01
9 changed files with 124 additions and 3 deletions

View File

@ -14,6 +14,7 @@ import { IUnleashServices } from '../../types/services';
import ContextService from '../../services/context-service';
import { Logger } from '../../logger';
import { IAuthRequest } from '../unleash-types';
import { IConstraint } from 'lib/types/model';
class ContextController extends Controller {
private logger: Logger;

View File

@ -337,6 +337,13 @@ export default class ProjectFeaturesController extends Controller {
res.status(200).json(updatedStrategy);
}
async validateConstraint(req: Request, res: Response): Promise<void> {
const constraint: IConstraint = { ...req.body };
await this.featureService.validateConstraint(constraint);
res.status(204).send();
}
async getStrategy(
req: IAuthRequest<StrategyIdParams, any, any, any>,
res: Response,

View File

@ -0,0 +1,25 @@
import { constraintNumberTypeSchema } from './constraint-value-types';
test('should require number', async () => {
try {
await constraintNumberTypeSchema.validateAsync('test');
} catch (error) {
expect(error.details[0].message).toEqual('"value" must be a number');
}
});
test('should allow strings that can be parsed to a number', async () => {
await constraintNumberTypeSchema.validateAsync('5');
});
test('should allow floating point numbers', async () => {
await constraintNumberTypeSchema.validateAsync(5.72);
});
test('should allow numbers', async () => {
await constraintNumberTypeSchema.validateAsync(5);
});
test('should allow negative numbers', async () => {
await constraintNumberTypeSchema.validateAsync(-5);
});

View File

@ -0,0 +1,3 @@
import joi from 'joi';
export const constraintNumberTypeSchema = joi.number();

View File

@ -39,6 +39,7 @@ import {
FeatureToggleDTO,
FeatureToggleLegacy,
FeatureToggleWithEnvironment,
IConstraint,
IEnvironmentDetail,
IFeatureEnvironmentInfo,
IFeatureOverview,
@ -50,7 +51,13 @@ import {
} from '../types/model';
import { IFeatureEnvironmentStore } from '../types/stores/feature-environment-store';
import { IFeatureToggleClientStore } from '../types/stores/feature-toggle-client-store';
import { DEFAULT_ENV } from '../util/constants';
import {
DATE_OPERATORS,
DEFAULT_ENV,
NUM_OPERATORS,
SEMVER_OPERATORS,
STRING_OPERATORS,
} from '../util/constants';
import { applyPatch, deepClone, Operation } from 'fast-json-patch';
import { OperationDeniedError } from '../error/operation-denied-error';
@ -63,6 +70,10 @@ interface IFeatureStrategyContext extends IFeatureContext {
environment: string;
}
const oneOf = (values: string[], match: string) => {
return values.some((value) => value === match);
};
class FeatureToggleService {
private logger: Logger;
@ -140,6 +151,25 @@ class FeatureToggleService {
}
}
validateConstraint(constraint: IConstraint): void {
const { operator } = constraint;
if (oneOf(NUM_OPERATORS, operator)) {
// Validate number value
}
if (oneOf(STRING_OPERATORS, operator)) {
// validate string values array
}
if (oneOf(SEMVER_OPERATORS, operator)) {
// validate semver
}
if (oneOf(DATE_OPERATORS, operator)) {
// validate dates
}
}
async patchFeature(
project: string,
featureName: string,

View File

@ -6,7 +6,10 @@ import { IUser } from './user';
export interface IConstraint {
contextName: string;
operator: string;
values: string[];
values?: string[];
value?: string;
inverted?: boolean;
caseInsensitive?: boolean;
}
export enum WeightType {
VARIABLE = 'variable',

View File

@ -5,3 +5,50 @@ export const ENVIRONMENT_PERMISSION_TYPE = 'environment';
export const PROJECT_PERMISSION_TYPE = 'project';
export const CUSTOM_ROLE_TYPE = 'custom';
/* CONTEXT FIELD OPERATORS */
export const NOT_IN = 'NOT_IN';
export const IN = 'IN';
export const STR_ENDS_WITH = 'STR_ENDS_WITH';
export const STR_STARTS_WITH = 'STR_STARTS_WITH';
export const STR_CONTAINS = 'STR_CONTAINS';
export const NUM_EQ = 'NUM_EQ';
export const NUM_GT = 'NUM_GT';
export const NUM_GTE = 'NUM_GTE';
export const NUM_LT = 'NUM_LT';
export const NUM_LTE = 'NUM_LTE';
export const DATE_AFTER = 'DATE_AFTER';
export const DATE_BEFORE = 'DATE_BEFORE';
export const SEMVER_EQ = 'SEMVER_EQ';
export const SEMVER_GT = 'SEMVER_GT';
export const SEMVER_LT = 'SEMVER_LT';
export const ALL_OPERATORS = [
NOT_IN,
IN,
STR_ENDS_WITH,
STR_STARTS_WITH,
STR_CONTAINS,
NUM_EQ,
NUM_GT,
NUM_GTE,
NUM_LT,
NUM_LTE,
DATE_AFTER,
DATE_BEFORE,
SEMVER_EQ,
SEMVER_GT,
SEMVER_LT,
];
export const STRING_OPERATORS = [
STR_ENDS_WITH,
STR_STARTS_WITH,
STR_CONTAINS,
IN,
NOT_IN,
];
export const NUM_OPERATORS = [NUM_EQ, NUM_GT, NUM_GTE, NUM_LT, NUM_LTE];
export const DATE_OPERATORS = [DATE_AFTER, DATE_BEFORE];
export const SEMVER_OPERATORS = [SEMVER_EQ, SEMVER_GT, SEMVER_LT];

View File

@ -0,0 +1,5 @@
import { constraintNumberTypeSchema } from 'lib/schema/constraint-value-types';
export const validateNumber = async (value: unknown): Promise<void> => {
await constraintNumberTypeSchema.validateAsync(value);
};

View File

@ -12,7 +12,7 @@ process.nextTick(async () => {
password: 'passord',
host: 'localhost',
port: 5432,
database: 'unleash',
database: 'contextfields',
ssl: false,
},
server: {