1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: implement createdByUserId for all features (#5725)

## About the changes

Implements setting values on the created_by_user_id column on the
features table in the db
This commit is contained in:
David Leek 2023-12-22 14:33:16 +01:00 committed by GitHub
parent 9d8487ad6e
commit 9ac1070f43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 213 additions and 36 deletions

View File

@ -41,6 +41,7 @@ test('returns 0 if no custom strategies are in use', async () => {
featureToggleStore.create('default', {
name: 'test-toggle-2',
createdByUserId: 9999,
});
strategyStore.createStrategy({
@ -68,6 +69,7 @@ test('counts custom strategies in use', async () => {
await featureToggleStore.create('default', {
name: 'test-toggle',
createdByUserId: 9999,
});
await strategyStore.createStrategy({
@ -112,6 +114,7 @@ test('increment sort order on each new insert', async () => {
await featureToggleStore.create('default', {
name: 'test-toggle-increment',
createdByUserId: 9999,
});
const { id: firstId } =

View File

@ -28,6 +28,7 @@ beforeAll(async () => {
await db.stores.featureToggleStore.create('default', {
name: FLAG_NAME,
createdByUserId: 9999,
});
});

View File

@ -661,6 +661,7 @@ test('should search features by project with operators', async () => {
await db.stores.featureToggleStore.create('project_b', {
name: 'my_feature_b',
createdByUserId: 9999,
});
await db.stores.projectStore.create({
@ -671,6 +672,7 @@ test('should search features by project with operators', async () => {
await db.stores.featureToggleStore.create('project_c', {
name: 'my_feature_c',
createdByUserId: 9999,
});
const { body } = await searchFeatures({

View File

@ -12,7 +12,10 @@ import {
IVariant,
} from 'lib/types/model';
import { LastSeenInput } from '../../../services/client-metrics/last-seen/last-seen-service';
import { EnvironmentFeatureNames } from '../feature-toggle-store';
import {
EnvironmentFeatureNames,
FeatureToggleInsert,
} from '../feature-toggle-store';
import { FeatureConfigurationClient } from '../types/feature-toggle-strategies-store-type';
import { IFeatureProjectUserParams } from '../feature-toggle-controller';
@ -104,7 +107,10 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
};
}
async create(project: string, data: FeatureToggle): Promise<FeatureToggle> {
async create(
project: string,
data: FeatureToggleInsert,
): Promise<FeatureToggle> {
const inserted: FeatureToggle = { ...data, project };
this.features.push(inserted);
return inserted;

View File

@ -1150,9 +1150,14 @@ class FeatureToggleService {
if (exists) {
let featureData;
if (isValidated) {
featureData = value;
featureData = { createdByUserId, ...value };
} else {
featureData = await featureMetadataSchema.validateAsync(value);
const validated =
await featureMetadataSchema.validateAsync(value);
featureData = {
createdByUserId,
...validated,
};
}
const featureName = featureData.name;
const createdToggle = await this.featureToggleStore.create(

View File

@ -49,6 +49,12 @@ export interface FeaturesTable {
impression_data: boolean;
archived?: boolean;
archived_at?: Date;
created_by_user_id?: number;
}
export interface FeatureToggleInsert
extends Omit<FeatureToggleDTO, 'createdByUserId'> {
createdByUserId: number;
}
interface VariantDTO {
@ -457,7 +463,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
return sortedVariants;
}
dtoToRow(project: string, data: FeatureToggleDTO): FeaturesTable {
insertToRow(project: string, data: FeatureToggleInsert): FeaturesTable {
const row = {
name: data.name,
description: data.description,
@ -467,20 +473,39 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
stale: data.stale,
created_at: data.createdAt,
impression_data: data.impressionData,
created_by_user_id: data.createdByUserId,
};
if (!row.created_at) {
delete row.created_at;
}
return row;
}
dtoToUpdateRow(
project: string,
data: FeatureToggleDTO,
): Omit<FeaturesTable, 'created_by_user_id'> {
const row = {
name: data.name,
description: data.description,
type: data.type,
project,
archived_at: data.archived ? new Date() : null,
stale: data.stale,
impression_data: data.impressionData,
};
return row;
}
async create(
project: string,
data: FeatureToggleDTO,
data: FeatureToggleInsert,
): Promise<FeatureToggle> {
try {
const row = await this.db(TABLE)
.insert(this.dtoToRow(project, data))
.insert(this.insertToRow(project, data))
.returning(FEATURE_COLUMNS);
return this.rowToFeature(row[0]);
@ -504,7 +529,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
): Promise<FeatureToggle> {
const row = await this.db(TABLE)
.where({ name: data.name })
.update(this.dtoToRow(project, data))
.update(this.dtoToUpdateRow(project, data))
.returning(FEATURE_COLUMNS);
return this.rowToFeature(row[0]);

View File

@ -100,14 +100,17 @@ test('Should get archived toggles via project', async () => {
await db.stores.featureToggleStore.create('proj-1', {
name: 'feat-proj-1',
archived: true,
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('proj-2', {
name: 'feat-proj-2',
archived: true,
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('proj-2', {
name: 'feat-proj-2-2',
archived: true,
createdByUserId: 9999,
});
await app.request
@ -151,6 +154,7 @@ test('Should disable all environments when reviving a toggle', async () => {
await db.stores.featureToggleStore.create('default', {
name: 'feat-proj-1',
archived: true,
createdByUserId: 9999,
});
await db.stores.environmentStore.create({

View File

@ -5,6 +5,7 @@ import {
IFeatureToggleStore,
IProjectStore,
} from '../../../types';
import { FeatureToggleInsert } from '../feature-toggle-store';
let stores;
let db;
@ -49,10 +50,11 @@ describe('potentially_stale marking', () => {
};
test('it returns an empty list if no toggles were updated', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'release',
createdByUserId: 9999,
},
];
await Promise.all(
@ -68,14 +70,16 @@ describe('potentially_stale marking', () => {
});
test('it returns only updated toggles', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'release',
createdByUserId: 9999,
},
{
name: 'feature2',
type: 'kill-switch',
createdByUserId: 9999,
},
];
await Promise.all(
@ -102,13 +106,13 @@ describe('potentially_stale marking', () => {
])(
'it marks toggles based on their type (days elapsed: %s)',
async (daysElapsed, expectedMarkedFeatures) => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
'release',
'experiment',
'operational',
'kill-switch',
'permission',
].map((type) => ({ name: type, type }));
].map((type) => ({ name: type, type, createdByUserId: 9999 }));
await Promise.all(
features.map((feature) =>
featureToggleStore.create('default', feature),
@ -143,11 +147,12 @@ describe('potentially_stale marking', () => {
},
);
test('it does not mark toggles already flagged as stale', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'release',
stale: true,
createdByUserId: 9999,
},
];
await Promise.all(
@ -163,10 +168,11 @@ describe('potentially_stale marking', () => {
});
test('it does not return toggles previously marked as potentially_stale', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'release',
createdByUserId: 9999,
},
];
await Promise.all(
@ -197,10 +203,11 @@ describe('potentially_stale marking', () => {
describe('changing feature types', () => {
test("if a potentially stale feature changes to a type that shouldn't be stale, it's 'potentially_stale' marker is removed.", async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'release',
createdByUserId: 9999,
},
];
await Promise.all(
@ -247,10 +254,11 @@ describe('potentially_stale marking', () => {
});
test('if a fresh feature changes to a type that should be stale, it gets marked as potentially stale', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'kill-switch',
createdByUserId: 9999,
},
];
await Promise.all(
@ -280,11 +288,12 @@ describe('potentially_stale marking', () => {
});
test('if a stale feature changes to a type that should be stale, it does not get marked as potentially stale', async () => {
const features: FeatureToggleDTO[] = [
const features: FeatureToggleInsert[] = [
{
name: 'feature1',
type: 'kill-switch',
stale: true,
createdByUserId: 9999,
},
];
await Promise.all(
@ -314,9 +323,15 @@ describe('potentially_stale marking', () => {
name: 'MyProject',
description: 'MyProject',
});
await featureToggleStore.create('default', { name: 'featureA' });
await featureToggleStore.create('default', {
name: 'featureA',
createdByUserId: 9999,
});
await featureToggleStore.create('MyProject', { name: 'featureB' });
await featureToggleStore.create('MyProject', {
name: 'featureB',
createdByUserId: 9999,
});
const playgroundFeatures =
await featureToggleStore.getPlaygroundFeatures({

View File

@ -15,7 +15,10 @@ beforeAll(async () => {
stores = db.stores;
featureStrategiesStore = stores.featureStrategiesStore;
featureToggleStore = stores.featureToggleStore;
await featureToggleStore.create('default', { name: featureName });
await featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
});
afterAll(async () => {
@ -74,8 +77,14 @@ test('Can successfully update project for all strategies belonging to feature',
test('Can query for features with tags', async () => {
const tag = { type: 'simple', value: 'hello-tags' };
await stores.tagStore.createTag(tag);
await featureToggleStore.create('default', { name: 'to-be-tagged' });
await featureToggleStore.create('default', { name: 'not-tagged' });
await featureToggleStore.create('default', {
name: 'to-be-tagged',
createdByUserId: 9999,
});
await featureToggleStore.create('default', {
name: 'not-tagged',
createdByUserId: 9999,
});
await stores.featureTagStore.tagFeature('to-be-tagged', tag);
const features = await featureStrategiesStore.getFeatureOverview({
projectId: 'default',
@ -87,9 +96,11 @@ test('Can query for features with tags', async () => {
test('Can query for features with namePrefix', async () => {
await featureToggleStore.create('default', {
name: 'nameprefix-to-be-hit',
createdByUserId: 9999,
});
await featureToggleStore.create('default', {
name: 'nameprefix-not-be-hit',
createdByUserId: 9999,
});
const features = await featureStrategiesStore.getFeatureOverview({
projectId: 'default',
@ -103,12 +114,15 @@ test('Can query for features with namePrefix and tags', async () => {
await stores.tagStore.createTag(tag);
await featureToggleStore.create('default', {
name: 'to-be-tagged-nameprefix-and-tags',
createdByUserId: 9999,
});
await featureToggleStore.create('default', {
name: 'not-tagged-nameprefix-and-tags',
createdByUserId: 9999,
});
await featureToggleStore.create('default', {
name: 'tagged-but-not-hit-nameprefix-and-tags',
createdByUserId: 9999,
});
await stores.featureTagStore.tagFeature(
'to-be-tagged-nameprefix-and-tags',

View File

@ -40,7 +40,10 @@ test('Should not be possible to update feature toggle without permission', async
const url = '/api/admin/projects/default/features';
const name = 'auth.toggle.update';
await db.stores.featureToggleStore.create('default', { name });
await db.stores.featureToggleStore.create('default', {
name,
createdByUserId: 9999,
});
await app.services.userService.createUser({
email,
@ -62,7 +65,10 @@ test('Should be possible to update feature toggle with permission', async () =>
const url = '/api/admin/projects/default/features';
const name = 'auth.toggle.update2';
await db.stores.featureToggleStore.create('default', { name });
await db.stores.featureToggleStore.create('default', {
name,
createdByUserId: 9999,
});
await app.services.userService.createUser({
email,

View File

@ -2574,6 +2574,7 @@ test('should reject invalid constraint values for multi-valued constraints', asy
const toggle = await db.stores.featureToggleStore.create(project.id, {
name: uuidv4(),
impressionData: true,
createdByUserId: 9999,
});
const mockStrategy = (values: string[]) => ({
@ -2621,6 +2622,7 @@ test('should add default constraint values for single-valued constraints', async
const toggle = await db.stores.featureToggleStore.create(project.id, {
name: uuidv4(),
impressionData: true,
createdByUserId: 9999,
});
const constraintValue = {
@ -2680,6 +2682,7 @@ test('should allow long parameter values', async () => {
const toggle = await db.stores.featureToggleStore.create(project.id, {
name: uuidv4(),
createdByUserId: 9999,
});
const strategy = {
@ -2988,9 +2991,11 @@ test('Can filter based on tags', async () => {
await db.stores.tagStore.createTag(tag);
await db.stores.featureToggleStore.create('default', {
name: 'to-be-tagged',
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('default', {
name: 'not-tagged',
createdByUserId: 9999,
});
await db.stores.featureTagStore.tagFeature('to-be-tagged', tag, TESTUSERID);
await app.request
@ -3003,9 +3008,11 @@ test('Can filter based on tags', async () => {
test('Can query for features with namePrefix', async () => {
await db.stores.featureToggleStore.create('default', {
name: 'nameprefix-to-be-hit',
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('default', {
name: 'nameprefix-not-be-hit',
createdByUserId: 9999,
});
await app.request
.get('/api/admin/projects/default/features?namePrefix=nameprefix-to')
@ -3019,12 +3026,15 @@ test('Can query for features with namePrefix and tags', async () => {
await db.stores.tagStore.createTag(tag);
await db.stores.featureToggleStore.create('default', {
name: 'to-be-tagged-nameprefix-and-tags',
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('default', {
name: 'not-tagged-nameprefix-and-tags',
createdByUserId: 9999,
});
await db.stores.featureToggleStore.create('default', {
name: 'tagged-but-not-hit-nameprefix-and-tags',
createdByUserId: 9999,
});
await db.stores.featureTagStore.tagFeature(
'to-be-tagged-nameprefix-and-tags',
@ -3054,18 +3064,21 @@ test('Can query for two tags at the same time. Tags are ORed together', async ()
'default',
{
name: 'tagged-with-first-tag',
createdByUserId: 9999,
},
);
const taggedWithSecond = await db.stores.featureToggleStore.create(
'default',
{
name: 'tagged-with-second-tag',
createdByUserId: 9999,
},
);
const taggedWithBoth = await db.stores.featureToggleStore.create(
'default',
{
name: 'tagged-with-both-tags',
createdByUserId: 9999,
},
);
await db.stores.featureTagStore.tagFeature(

View File

@ -5,6 +5,7 @@ import {
IFeatureTypeCount,
IVariant,
} from '../../../types/model';
import { FeatureToggleInsert } from '../feature-toggle-store';
import { Store } from '../../../types/stores/store';
import { LastSeenInput } from '../../../services/client-metrics/last-seen/last-seen-service';
import { FeatureConfigurationClient } from './feature-toggle-strategies-store-type';
@ -24,7 +25,7 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
getProjectId(name: string): Promise<string | undefined>;
create(project: string, data: FeatureToggleDTO): Promise<FeatureToggle>;
create(project: string, data: FeatureToggleInsert): Promise<FeatureToggle>;
update(project: string, data: FeatureToggleDTO): Promise<FeatureToggle>;

View File

@ -52,6 +52,7 @@ test('Can connect environment to project', async () => {
type: 'release',
description: '',
stale: false,
createdByUserId: 9999,
});
await service.addEnvironmentToProject(
'test-connection',
@ -93,6 +94,7 @@ test('Can remove environment from project', async () => {
});
await stores.featureToggleStore.create('default', {
name: 'removal-test',
createdByUserId: 9999,
});
await service.removeEnvironmentFromProject(
'test-connection',
@ -285,6 +287,7 @@ test('When given overrides should remap projects to override environments', asyn
type: 'release',
description: '',
stale: false,
createdByUserId: 9999,
});
await service.addEnvironmentToProject(

View File

@ -188,6 +188,7 @@ test('schema allow yes=<string nbr>', () => {
test('should return a 400 when required fields are missing', async () => {
stores.featureToggleStore.create('default', {
name: 'toggleLastSeen',
createdByUserId: 9999,
});
await request
.post('/api/client/metrics')
@ -209,6 +210,7 @@ test('should return a 400 when required fields are missing', async () => {
test('should return a 200 if required fields are there', async () => {
stores.featureToggleStore.create('default', {
name: 'theOtherToggleLastSeen',
createdByUserId: 9999,
});
await request
.post('/api/client/metrics')

View File

@ -104,6 +104,7 @@ export const featureMetadataSchema = joi
.unique((a, b) => a.name === b.name)
.optional()
.items(variantsSchema),
createdByUserId: joi.number(),
})
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });

View File

@ -43,6 +43,7 @@ async function setupV3VariantsCompatibilityScenario(
const stores = createStores();
await stores.featureToggleStore.create('some-project', {
name: 'Feature-with-variants',
createdByUserId: 9999,
});
let sortOrder = 1;
envs.forEach(async (env) => {
@ -112,6 +113,7 @@ test('should not import an existing feature', async () => {
name: 'new-feature',
enabled: true,
strategies: [{ name: 'default' }],
createdByUserId: 9999,
},
],
};
@ -137,6 +139,7 @@ test('should not keep existing feature if drop-before-import', async () => {
name: 'new-feature',
enabled: true,
strategies: [{ name: 'default' }],
createdByUserId: 9999,
},
],
};
@ -289,6 +292,7 @@ test('should export featureToggles', async () => {
await stores.featureToggleStore.create('default', {
name: 'a-feature',
createdByUserId: 9999,
});
const data = await stateService.export({ includeFeatureToggles: true });
@ -303,6 +307,7 @@ test('archived feature toggles should not be included', async () => {
await stores.featureToggleStore.create('default', {
name: 'a-feature',
archived: true,
createdByUserId: 9999,
});
const data = await stateService.export({ includeFeatureToggles: true });
@ -315,6 +320,7 @@ test('featureStrategy connected to an archived feature toggle should not be incl
await stores.featureToggleStore.create('default', {
name: featureName,
archived: true,
createdByUserId: 9999,
});
await stores.featureStrategiesStore.createStrategyFeatureEnv({
@ -334,6 +340,7 @@ test('featureStrategy connected to a feature should be included', async () => {
const featureName = 'fstrat-feature';
await stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await stores.featureStrategiesStore.createStrategyFeatureEnv({
@ -662,6 +669,7 @@ test('exporting to new format works', async () => {
});
await stores.featureToggleStore.create('fancy', {
name: 'Some-feature',
createdByUserId: 9999,
});
await stores.strategyStore.createStrategy({
name: 'format',
@ -724,6 +732,7 @@ test('featureStrategies can keep existing', async () => {
});
await stores.featureToggleStore.create('fancy', {
name: 'Some-feature',
createdByUserId: 9999,
});
await stores.strategyStore.createStrategy({
name: 'format',
@ -779,6 +788,7 @@ test('featureStrategies should not keep existing if dropBeforeImport', async ()
});
await stores.featureToggleStore.create('fancy', {
name: 'Some-feature',
createdByUserId: 9999,
});
await stores.strategyStore.createStrategy({
name: 'format',

View File

@ -396,7 +396,10 @@ export default class StateService {
.filter(filterExisting(keepExisting, oldToggles))
.filter(filterEqual(oldToggles))
.map(async (feature) => {
await this.toggleStore.create(feature.project, feature);
await this.toggleStore.create(feature.project, {
createdByUserId: userId,
...feature,
});
await this.featureEnvironmentStore.connectFeatureToEnvironmentsForProject(
feature.name,
feature.project,

View File

@ -181,7 +181,10 @@ test('counts toggles', async () => {
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
enabled: true,
});
await stores.featureToggleStore.create('project', { name: uuidv4() });
await stores.featureToggleStore.create('project', {
name: uuidv4(),
createdByUserId: 9999,
});
await stores.strategyStore.createStrategy({
name: uuidv4(),
editable: true,
@ -237,7 +240,10 @@ test('counts custom strategies', async () => {
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
enabled: true,
});
await stores.featureToggleStore.create('project', { name: toggleName });
await stores.featureToggleStore.create('project', {
name: toggleName,
createdByUserId: 9999,
});
await stores.strategyStore.createStrategy({
name: strategyName,
editable: true,

View File

@ -59,6 +59,7 @@ export interface FeatureToggleDTO {
createdAt?: Date;
impressionData?: boolean;
variants?: IVariant[];
createdByUserId?: number;
}
export interface FeatureToggle extends FeatureToggleDTO {

View File

@ -20,7 +20,10 @@ afterAll(async () => {
});
test('should return instance statistics', async () => {
stores.featureToggleStore.create('default', { name: 'TestStats1' });
stores.featureToggleStore.create('default', {
name: 'TestStats1',
createdByUserId: 9999,
});
return app.request
.get('/api/admin/instance-admin/statistics')
@ -62,8 +65,14 @@ test('should return signed instance statistics', async () => {
});
test('should return instance statistics as CVS', async () => {
stores.featureToggleStore.create('default', { name: 'TestStats2' });
stores.featureToggleStore.create('default', { name: 'TestStats3' });
stores.featureToggleStore.create('default', {
name: 'TestStats2',
createdByUserId: 9999,
});
stores.featureToggleStore.create('default', {
name: 'TestStats3',
createdByUserId: 9999,
});
const res = await app.request
.get('/api/admin/instance-admin/statistics/csv')

View File

@ -37,7 +37,10 @@ afterAll(async () => {
test('Can get variants for a feature', async () => {
const featureName = 'feature-variants';
const variantName = 'fancy-variant';
await db.stores.featureToggleStore.create('default', { name: featureName });
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
'default',
@ -110,6 +113,7 @@ test('Can patch variants for a feature and get a response of new variant', async
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -151,6 +155,7 @@ test('Can patch variants for a feature patches all environments independently',
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -237,6 +242,7 @@ test('Can push variants to multiple environments', async () => {
});
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -339,6 +345,7 @@ test('Can add variant for a feature', async () => {
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -394,6 +401,7 @@ test('Can remove variant for a feature', async () => {
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -438,6 +446,7 @@ test('PUT overwrites current variant on feature', async () => {
];
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -492,6 +501,7 @@ test('PUTing an invalid variant throws 400 exception', async () => {
const featureName = 'variants-validation-feature';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
const invalidJson = [
@ -518,6 +528,7 @@ test('Invalid variant in PATCH also throws 400 exception', async () => {
const featureName = 'patch-validation-feature';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -553,6 +564,7 @@ test('PATCHING with all variable weightTypes forces weights to sum to no less th
const featureName = 'variants-validation-with-all-variable-weights';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -647,6 +659,7 @@ test('PATCHING with no variable variants fails with 400', async () => {
const featureName = 'variants-validation-with-no-variable-weights';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName,
@ -681,6 +694,7 @@ test('Patching with a fixed variant and variable variants splits remaining weigh
const featureName = 'variants-fixed-and-variable';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -778,6 +792,7 @@ test('Multiple fixed variants gets added together to decide how much weight vari
const featureName = 'variants-multiple-fixed-and-variable';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -829,6 +844,7 @@ test('If sum of fixed variant weight exceed 1000 fails with 400', async () => {
const featureName = 'variants-fixed-weight-over-1000';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -876,6 +892,7 @@ test('If sum of fixed variant weight equals 1000 variable variants gets weight 0
const featureName = 'variants-fixed-weight-equals-1000-no-variable-weight';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -944,6 +961,7 @@ test('PATCH endpoint validates uniqueness of variant names', async () => {
];
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -989,6 +1007,7 @@ test('PUT endpoint validates uniqueness of variant names', async () => {
const featureName = 'variants-put-uniqueness-names';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -1025,6 +1044,7 @@ test('Variants should be sorted by their name when PUT', async () => {
const featureName = 'variants-sort-by-name';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
@ -1074,6 +1094,7 @@ test('Variants should be sorted by name when PATCHed as well', async () => {
const featureName = 'variants-patch-sort-by-name';
await db.stores.featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(

View File

@ -118,6 +118,7 @@ export const seedDatabaseForPlaygroundTest = async (
...feature,
createdAt: undefined,
variants: null,
createdByUserId: 9999,
},
);

View File

@ -52,11 +52,13 @@ test('Project with no stale toggles should have 100% health rating', async () =>
name: 'health-rating-not-stale',
description: 'new',
stale: false,
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating', {
name: 'health-rating-not-stale-2',
description: 'new too',
stale: false,
createdByUserId: 9999,
});
const rating =
await projectHealthService.calculateHealthRating(savedProject);
@ -74,21 +76,25 @@ test('Project with two stale toggles and two non stale should have 50% health ra
name: 'health-rating-2-not-stale',
description: 'new',
stale: false,
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating-2', {
name: 'health-rating-2-not-stale-2',
description: 'new too',
stale: false,
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating-2', {
name: 'health-rating-2-stale-1',
description: 'stale',
stale: true,
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating-2', {
name: 'health-rating-2-stale-2',
description: 'stale too',
stale: true,
createdByUserId: 9999,
});
const rating =
await projectHealthService.calculateHealthRating(savedProject);
@ -106,6 +112,7 @@ test('Project with one non-stale, one potentially stale and one stale should hav
name: 'health-rating-3-not-stale',
description: 'new',
stale: false,
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating-3', {
name: 'health-rating-3-potentially-stale',
@ -113,11 +120,13 @@ test('Project with one non-stale, one potentially stale and one stale should hav
type: 'release',
stale: false,
createdAt: new Date(Date.UTC(2020, 1, 1)),
createdByUserId: 9999,
});
await stores.featureToggleStore.create('health-rating-3', {
name: 'health-rating-3-stale',
description: 'stale',
stale: true,
createdByUserId: 9999,
});
const rating =
await projectHealthService.calculateHealthRating(savedProject);

View File

@ -177,6 +177,7 @@ test('should not be able to delete project with toggles', async () => {
await projectService.createProject(project, user);
await stores.featureToggleStore.create(project.id, {
name: 'test-project-delete',
createdByUserId: 9999,
});
try {
@ -1461,9 +1462,11 @@ test('should only count active feature toggles for project', async () => {
await stores.featureToggleStore.create(project.id, {
name: 'only-active-t1',
createdByUserId: 9999,
});
await stores.featureToggleStore.create(project.id, {
name: 'only-active-t2',
createdByUserId: 9999,
});
await featureToggleService.archiveToggle('only-active-t2', user);
@ -1486,6 +1489,7 @@ test('should list projects with all features archived', async () => {
await stores.featureToggleStore.create(project.id, {
name: 'archived-toggle',
createdByUserId: 9999,
});
await featureToggleService.archiveToggle('archived-toggle', user);
@ -2088,6 +2092,7 @@ test('deleting a project with archived toggles should result in any remaining ar
await stores.featureToggleStore.create(project.id, {
name: toggleName,
createdByUserId: 9999,
});
await stores.featureToggleStore.archive(toggleName);

View File

@ -31,7 +31,10 @@ test('Setting enabled to same as existing value returns 0', async () => {
enabled: true,
type: 'test',
});
await featureStore.create('default', { name: featureName });
await featureStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await featureEnvironmentStore.connectProject(envName, 'default');
await featureEnvironmentStore.connectFeatures(envName, 'default');
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(
@ -54,7 +57,10 @@ test('Setting enabled to not existing value returns 1', async () => {
enabled: true,
type: 'test',
});
await featureStore.create('default', { name: featureName });
await featureStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
await featureEnvironmentStore.connectProject(envName, 'default');
await featureEnvironmentStore.connectFeatures(envName, 'default');
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(

View File

@ -19,7 +19,10 @@ beforeAll(async () => {
featureTagStore = stores.featureTagStore;
featureToggleStore = stores.featureToggleStore;
await stores.tagStore.createTag(tag);
await featureToggleStore.create('default', { name: featureName });
await featureToggleStore.create('default', {
name: featureName,
createdByUserId: 9999,
});
});
afterAll(async () => {
@ -80,6 +83,7 @@ test('get all feature tags', async () => {
await featureTagStore.tagFeature(featureName, tag, TESTUSERID);
await featureToggleStore.create('default', {
name: 'some-other-toggle',
createdByUserId: 9999,
});
await featureTagStore.tagFeature('some-other-toggle', tag, TESTUSERID);
const all = await featureTagStore.getAll();
@ -89,6 +93,7 @@ test('get all feature tags', async () => {
test('should import feature tags', async () => {
await featureToggleStore.create('default', {
name: 'some-other-toggle-import',
createdByUserId: 9999,
});
await featureTagStore.tagFeatures([
{
@ -121,7 +126,7 @@ test('should throw not found error if feature does not exist', async () => {
test('Returns empty tag list for existing feature with no tags', async () => {
const name = 'feature.with.no.tags';
await featureToggleStore.create('default', { name });
await featureToggleStore.create('default', { name, createdByUserId: 9999 });
const tags = await featureTagStore.getAllTagsForFeature(name);
expect(tags).toHaveLength(0);
});