mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01: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:
parent
9d8487ad6e
commit
9ac1070f43
@ -41,6 +41,7 @@ test('returns 0 if no custom strategies are in use', async () => {
|
|||||||
|
|
||||||
featureToggleStore.create('default', {
|
featureToggleStore.create('default', {
|
||||||
name: 'test-toggle-2',
|
name: 'test-toggle-2',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
strategyStore.createStrategy({
|
strategyStore.createStrategy({
|
||||||
@ -68,6 +69,7 @@ test('counts custom strategies in use', async () => {
|
|||||||
|
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'test-toggle',
|
name: 'test-toggle',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await strategyStore.createStrategy({
|
await strategyStore.createStrategy({
|
||||||
@ -112,6 +114,7 @@ test('increment sort order on each new insert', async () => {
|
|||||||
|
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'test-toggle-increment',
|
name: 'test-toggle-increment',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { id: firstId } =
|
const { id: firstId } =
|
||||||
|
|||||||
@ -28,6 +28,7 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: FLAG_NAME,
|
name: FLAG_NAME,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -661,6 +661,7 @@ test('should search features by project with operators', async () => {
|
|||||||
|
|
||||||
await db.stores.featureToggleStore.create('project_b', {
|
await db.stores.featureToggleStore.create('project_b', {
|
||||||
name: 'my_feature_b',
|
name: 'my_feature_b',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.projectStore.create({
|
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', {
|
await db.stores.featureToggleStore.create('project_c', {
|
||||||
name: 'my_feature_c',
|
name: 'my_feature_c',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { body } = await searchFeatures({
|
const { body } = await searchFeatures({
|
||||||
|
|||||||
@ -12,7 +12,10 @@ import {
|
|||||||
IVariant,
|
IVariant,
|
||||||
} from 'lib/types/model';
|
} from 'lib/types/model';
|
||||||
import { LastSeenInput } from '../../../services/client-metrics/last-seen/last-seen-service';
|
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 { FeatureConfigurationClient } from '../types/feature-toggle-strategies-store-type';
|
||||||
import { IFeatureProjectUserParams } from '../feature-toggle-controller';
|
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 };
|
const inserted: FeatureToggle = { ...data, project };
|
||||||
this.features.push(inserted);
|
this.features.push(inserted);
|
||||||
return inserted;
|
return inserted;
|
||||||
|
|||||||
@ -1150,9 +1150,14 @@ class FeatureToggleService {
|
|||||||
if (exists) {
|
if (exists) {
|
||||||
let featureData;
|
let featureData;
|
||||||
if (isValidated) {
|
if (isValidated) {
|
||||||
featureData = value;
|
featureData = { createdByUserId, ...value };
|
||||||
} else {
|
} else {
|
||||||
featureData = await featureMetadataSchema.validateAsync(value);
|
const validated =
|
||||||
|
await featureMetadataSchema.validateAsync(value);
|
||||||
|
featureData = {
|
||||||
|
createdByUserId,
|
||||||
|
...validated,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const featureName = featureData.name;
|
const featureName = featureData.name;
|
||||||
const createdToggle = await this.featureToggleStore.create(
|
const createdToggle = await this.featureToggleStore.create(
|
||||||
|
|||||||
@ -49,6 +49,12 @@ export interface FeaturesTable {
|
|||||||
impression_data: boolean;
|
impression_data: boolean;
|
||||||
archived?: boolean;
|
archived?: boolean;
|
||||||
archived_at?: Date;
|
archived_at?: Date;
|
||||||
|
created_by_user_id?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeatureToggleInsert
|
||||||
|
extends Omit<FeatureToggleDTO, 'createdByUserId'> {
|
||||||
|
createdByUserId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VariantDTO {
|
interface VariantDTO {
|
||||||
@ -457,7 +463,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
return sortedVariants;
|
return sortedVariants;
|
||||||
}
|
}
|
||||||
|
|
||||||
dtoToRow(project: string, data: FeatureToggleDTO): FeaturesTable {
|
insertToRow(project: string, data: FeatureToggleInsert): FeaturesTable {
|
||||||
const row = {
|
const row = {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
description: data.description,
|
description: data.description,
|
||||||
@ -467,20 +473,39 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
stale: data.stale,
|
stale: data.stale,
|
||||||
created_at: data.createdAt,
|
created_at: data.createdAt,
|
||||||
impression_data: data.impressionData,
|
impression_data: data.impressionData,
|
||||||
|
created_by_user_id: data.createdByUserId,
|
||||||
};
|
};
|
||||||
if (!row.created_at) {
|
if (!row.created_at) {
|
||||||
delete 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;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(
|
async create(
|
||||||
project: string,
|
project: string,
|
||||||
data: FeatureToggleDTO,
|
data: FeatureToggleInsert,
|
||||||
): Promise<FeatureToggle> {
|
): Promise<FeatureToggle> {
|
||||||
try {
|
try {
|
||||||
const row = await this.db(TABLE)
|
const row = await this.db(TABLE)
|
||||||
.insert(this.dtoToRow(project, data))
|
.insert(this.insertToRow(project, data))
|
||||||
.returning(FEATURE_COLUMNS);
|
.returning(FEATURE_COLUMNS);
|
||||||
|
|
||||||
return this.rowToFeature(row[0]);
|
return this.rowToFeature(row[0]);
|
||||||
@ -504,7 +529,7 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
): Promise<FeatureToggle> {
|
): Promise<FeatureToggle> {
|
||||||
const row = await this.db(TABLE)
|
const row = await this.db(TABLE)
|
||||||
.where({ name: data.name })
|
.where({ name: data.name })
|
||||||
.update(this.dtoToRow(project, data))
|
.update(this.dtoToUpdateRow(project, data))
|
||||||
.returning(FEATURE_COLUMNS);
|
.returning(FEATURE_COLUMNS);
|
||||||
|
|
||||||
return this.rowToFeature(row[0]);
|
return this.rowToFeature(row[0]);
|
||||||
|
|||||||
@ -100,14 +100,17 @@ test('Should get archived toggles via project', async () => {
|
|||||||
await db.stores.featureToggleStore.create('proj-1', {
|
await db.stores.featureToggleStore.create('proj-1', {
|
||||||
name: 'feat-proj-1',
|
name: 'feat-proj-1',
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('proj-2', {
|
await db.stores.featureToggleStore.create('proj-2', {
|
||||||
name: 'feat-proj-2',
|
name: 'feat-proj-2',
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('proj-2', {
|
await db.stores.featureToggleStore.create('proj-2', {
|
||||||
name: 'feat-proj-2-2',
|
name: 'feat-proj-2-2',
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.request
|
await app.request
|
||||||
@ -151,6 +154,7 @@ test('Should disable all environments when reviving a toggle', async () => {
|
|||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'feat-proj-1',
|
name: 'feat-proj-1',
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.environmentStore.create({
|
await db.stores.environmentStore.create({
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
IFeatureToggleStore,
|
IFeatureToggleStore,
|
||||||
IProjectStore,
|
IProjectStore,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
import { FeatureToggleInsert } from '../feature-toggle-store';
|
||||||
|
|
||||||
let stores;
|
let stores;
|
||||||
let db;
|
let db;
|
||||||
@ -49,10 +50,11 @@ describe('potentially_stale marking', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test('it returns an empty list if no toggles were updated', async () => {
|
test('it returns an empty list if no toggles were updated', async () => {
|
||||||
const features: FeatureToggleDTO[] = [
|
const features: FeatureToggleInsert[] = [
|
||||||
{
|
{
|
||||||
name: 'feature1',
|
name: 'feature1',
|
||||||
type: 'release',
|
type: 'release',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -68,14 +70,16 @@ describe('potentially_stale marking', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('it returns only updated toggles', async () => {
|
test('it returns only updated toggles', async () => {
|
||||||
const features: FeatureToggleDTO[] = [
|
const features: FeatureToggleInsert[] = [
|
||||||
{
|
{
|
||||||
name: 'feature1',
|
name: 'feature1',
|
||||||
type: 'release',
|
type: 'release',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'feature2',
|
name: 'feature2',
|
||||||
type: 'kill-switch',
|
type: 'kill-switch',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -102,13 +106,13 @@ describe('potentially_stale marking', () => {
|
|||||||
])(
|
])(
|
||||||
'it marks toggles based on their type (days elapsed: %s)',
|
'it marks toggles based on their type (days elapsed: %s)',
|
||||||
async (daysElapsed, expectedMarkedFeatures) => {
|
async (daysElapsed, expectedMarkedFeatures) => {
|
||||||
const features: FeatureToggleDTO[] = [
|
const features: FeatureToggleInsert[] = [
|
||||||
'release',
|
'release',
|
||||||
'experiment',
|
'experiment',
|
||||||
'operational',
|
'operational',
|
||||||
'kill-switch',
|
'kill-switch',
|
||||||
'permission',
|
'permission',
|
||||||
].map((type) => ({ name: type, type }));
|
].map((type) => ({ name: type, type, createdByUserId: 9999 }));
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
features.map((feature) =>
|
features.map((feature) =>
|
||||||
featureToggleStore.create('default', feature),
|
featureToggleStore.create('default', feature),
|
||||||
@ -143,11 +147,12 @@ describe('potentially_stale marking', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
test('it does not mark toggles already flagged as stale', async () => {
|
test('it does not mark toggles already flagged as stale', async () => {
|
||||||
const features: FeatureToggleDTO[] = [
|
const features: FeatureToggleInsert[] = [
|
||||||
{
|
{
|
||||||
name: 'feature1',
|
name: 'feature1',
|
||||||
type: 'release',
|
type: 'release',
|
||||||
stale: true,
|
stale: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -163,10 +168,11 @@ describe('potentially_stale marking', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('it does not return toggles previously marked as potentially_stale', async () => {
|
test('it does not return toggles previously marked as potentially_stale', async () => {
|
||||||
const features: FeatureToggleDTO[] = [
|
const features: FeatureToggleInsert[] = [
|
||||||
{
|
{
|
||||||
name: 'feature1',
|
name: 'feature1',
|
||||||
type: 'release',
|
type: 'release',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -197,10 +203,11 @@ describe('potentially_stale marking', () => {
|
|||||||
|
|
||||||
describe('changing feature types', () => {
|
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 () => {
|
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',
|
name: 'feature1',
|
||||||
type: 'release',
|
type: 'release',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
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 () => {
|
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',
|
name: 'feature1',
|
||||||
type: 'kill-switch',
|
type: 'kill-switch',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
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 () => {
|
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',
|
name: 'feature1',
|
||||||
type: 'kill-switch',
|
type: 'kill-switch',
|
||||||
stale: true,
|
stale: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -314,9 +323,15 @@ describe('potentially_stale marking', () => {
|
|||||||
name: 'MyProject',
|
name: 'MyProject',
|
||||||
description: '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 =
|
const playgroundFeatures =
|
||||||
await featureToggleStore.getPlaygroundFeatures({
|
await featureToggleStore.getPlaygroundFeatures({
|
||||||
|
|||||||
@ -15,7 +15,10 @@ beforeAll(async () => {
|
|||||||
stores = db.stores;
|
stores = db.stores;
|
||||||
featureStrategiesStore = stores.featureStrategiesStore;
|
featureStrategiesStore = stores.featureStrategiesStore;
|
||||||
featureToggleStore = stores.featureToggleStore;
|
featureToggleStore = stores.featureToggleStore;
|
||||||
await featureToggleStore.create('default', { name: featureName });
|
await featureToggleStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
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 () => {
|
test('Can query for features with tags', async () => {
|
||||||
const tag = { type: 'simple', value: 'hello-tags' };
|
const tag = { type: 'simple', value: 'hello-tags' };
|
||||||
await stores.tagStore.createTag(tag);
|
await stores.tagStore.createTag(tag);
|
||||||
await featureToggleStore.create('default', { name: 'to-be-tagged' });
|
await featureToggleStore.create('default', {
|
||||||
await featureToggleStore.create('default', { name: 'not-tagged' });
|
name: 'to-be-tagged',
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
await featureToggleStore.create('default', {
|
||||||
|
name: 'not-tagged',
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
await stores.featureTagStore.tagFeature('to-be-tagged', tag);
|
await stores.featureTagStore.tagFeature('to-be-tagged', tag);
|
||||||
const features = await featureStrategiesStore.getFeatureOverview({
|
const features = await featureStrategiesStore.getFeatureOverview({
|
||||||
projectId: 'default',
|
projectId: 'default',
|
||||||
@ -87,9 +96,11 @@ test('Can query for features with tags', async () => {
|
|||||||
test('Can query for features with namePrefix', async () => {
|
test('Can query for features with namePrefix', async () => {
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'nameprefix-to-be-hit',
|
name: 'nameprefix-to-be-hit',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'nameprefix-not-be-hit',
|
name: 'nameprefix-not-be-hit',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
const features = await featureStrategiesStore.getFeatureOverview({
|
const features = await featureStrategiesStore.getFeatureOverview({
|
||||||
projectId: 'default',
|
projectId: 'default',
|
||||||
@ -103,12 +114,15 @@ test('Can query for features with namePrefix and tags', async () => {
|
|||||||
await stores.tagStore.createTag(tag);
|
await stores.tagStore.createTag(tag);
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'to-be-tagged-nameprefix-and-tags',
|
name: 'to-be-tagged-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'not-tagged-nameprefix-and-tags',
|
name: 'not-tagged-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'tagged-but-not-hit-nameprefix-and-tags',
|
name: 'tagged-but-not-hit-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureTagStore.tagFeature(
|
await stores.featureTagStore.tagFeature(
|
||||||
'to-be-tagged-nameprefix-and-tags',
|
'to-be-tagged-nameprefix-and-tags',
|
||||||
|
|||||||
@ -40,7 +40,10 @@ test('Should not be possible to update feature toggle without permission', async
|
|||||||
const url = '/api/admin/projects/default/features';
|
const url = '/api/admin/projects/default/features';
|
||||||
const name = 'auth.toggle.update';
|
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({
|
await app.services.userService.createUser({
|
||||||
email,
|
email,
|
||||||
@ -62,7 +65,10 @@ test('Should be possible to update feature toggle with permission', async () =>
|
|||||||
const url = '/api/admin/projects/default/features';
|
const url = '/api/admin/projects/default/features';
|
||||||
const name = 'auth.toggle.update2';
|
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({
|
await app.services.userService.createUser({
|
||||||
email,
|
email,
|
||||||
|
|||||||
@ -2574,6 +2574,7 @@ test('should reject invalid constraint values for multi-valued constraints', asy
|
|||||||
const toggle = await db.stores.featureToggleStore.create(project.id, {
|
const toggle = await db.stores.featureToggleStore.create(project.id, {
|
||||||
name: uuidv4(),
|
name: uuidv4(),
|
||||||
impressionData: true,
|
impressionData: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockStrategy = (values: string[]) => ({
|
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, {
|
const toggle = await db.stores.featureToggleStore.create(project.id, {
|
||||||
name: uuidv4(),
|
name: uuidv4(),
|
||||||
impressionData: true,
|
impressionData: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const constraintValue = {
|
const constraintValue = {
|
||||||
@ -2680,6 +2682,7 @@ test('should allow long parameter values', async () => {
|
|||||||
|
|
||||||
const toggle = await db.stores.featureToggleStore.create(project.id, {
|
const toggle = await db.stores.featureToggleStore.create(project.id, {
|
||||||
name: uuidv4(),
|
name: uuidv4(),
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const strategy = {
|
const strategy = {
|
||||||
@ -2988,9 +2991,11 @@ test('Can filter based on tags', async () => {
|
|||||||
await db.stores.tagStore.createTag(tag);
|
await db.stores.tagStore.createTag(tag);
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'to-be-tagged',
|
name: 'to-be-tagged',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'not-tagged',
|
name: 'not-tagged',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureTagStore.tagFeature('to-be-tagged', tag, TESTUSERID);
|
await db.stores.featureTagStore.tagFeature('to-be-tagged', tag, TESTUSERID);
|
||||||
await app.request
|
await app.request
|
||||||
@ -3003,9 +3008,11 @@ test('Can filter based on tags', async () => {
|
|||||||
test('Can query for features with namePrefix', async () => {
|
test('Can query for features with namePrefix', async () => {
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'nameprefix-to-be-hit',
|
name: 'nameprefix-to-be-hit',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'nameprefix-not-be-hit',
|
name: 'nameprefix-not-be-hit',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await app.request
|
await app.request
|
||||||
.get('/api/admin/projects/default/features?namePrefix=nameprefix-to')
|
.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.tagStore.createTag(tag);
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'to-be-tagged-nameprefix-and-tags',
|
name: 'to-be-tagged-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'not-tagged-nameprefix-and-tags',
|
name: 'not-tagged-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: 'tagged-but-not-hit-nameprefix-and-tags',
|
name: 'tagged-but-not-hit-nameprefix-and-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureTagStore.tagFeature(
|
await db.stores.featureTagStore.tagFeature(
|
||||||
'to-be-tagged-nameprefix-and-tags',
|
'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',
|
'default',
|
||||||
{
|
{
|
||||||
name: 'tagged-with-first-tag',
|
name: 'tagged-with-first-tag',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const taggedWithSecond = await db.stores.featureToggleStore.create(
|
const taggedWithSecond = await db.stores.featureToggleStore.create(
|
||||||
'default',
|
'default',
|
||||||
{
|
{
|
||||||
name: 'tagged-with-second-tag',
|
name: 'tagged-with-second-tag',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const taggedWithBoth = await db.stores.featureToggleStore.create(
|
const taggedWithBoth = await db.stores.featureToggleStore.create(
|
||||||
'default',
|
'default',
|
||||||
{
|
{
|
||||||
name: 'tagged-with-both-tags',
|
name: 'tagged-with-both-tags',
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await db.stores.featureTagStore.tagFeature(
|
await db.stores.featureTagStore.tagFeature(
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
IFeatureTypeCount,
|
IFeatureTypeCount,
|
||||||
IVariant,
|
IVariant,
|
||||||
} from '../../../types/model';
|
} from '../../../types/model';
|
||||||
|
import { FeatureToggleInsert } from '../feature-toggle-store';
|
||||||
import { Store } from '../../../types/stores/store';
|
import { Store } from '../../../types/stores/store';
|
||||||
import { LastSeenInput } from '../../../services/client-metrics/last-seen/last-seen-service';
|
import { LastSeenInput } from '../../../services/client-metrics/last-seen/last-seen-service';
|
||||||
import { FeatureConfigurationClient } from './feature-toggle-strategies-store-type';
|
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>;
|
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>;
|
update(project: string, data: FeatureToggleDTO): Promise<FeatureToggle>;
|
||||||
|
|
||||||
|
|||||||
@ -52,6 +52,7 @@ test('Can connect environment to project', async () => {
|
|||||||
type: 'release',
|
type: 'release',
|
||||||
description: '',
|
description: '',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await service.addEnvironmentToProject(
|
await service.addEnvironmentToProject(
|
||||||
'test-connection',
|
'test-connection',
|
||||||
@ -93,6 +94,7 @@ test('Can remove environment from project', async () => {
|
|||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('default', {
|
await stores.featureToggleStore.create('default', {
|
||||||
name: 'removal-test',
|
name: 'removal-test',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await service.removeEnvironmentFromProject(
|
await service.removeEnvironmentFromProject(
|
||||||
'test-connection',
|
'test-connection',
|
||||||
@ -285,6 +287,7 @@ test('When given overrides should remap projects to override environments', asyn
|
|||||||
type: 'release',
|
type: 'release',
|
||||||
description: '',
|
description: '',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await service.addEnvironmentToProject(
|
await service.addEnvironmentToProject(
|
||||||
|
|||||||
@ -188,6 +188,7 @@ test('schema allow yes=<string nbr>', () => {
|
|||||||
test('should return a 400 when required fields are missing', async () => {
|
test('should return a 400 when required fields are missing', async () => {
|
||||||
stores.featureToggleStore.create('default', {
|
stores.featureToggleStore.create('default', {
|
||||||
name: 'toggleLastSeen',
|
name: 'toggleLastSeen',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await request
|
await request
|
||||||
.post('/api/client/metrics')
|
.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 () => {
|
test('should return a 200 if required fields are there', async () => {
|
||||||
stores.featureToggleStore.create('default', {
|
stores.featureToggleStore.create('default', {
|
||||||
name: 'theOtherToggleLastSeen',
|
name: 'theOtherToggleLastSeen',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await request
|
await request
|
||||||
.post('/api/client/metrics')
|
.post('/api/client/metrics')
|
||||||
|
|||||||
@ -104,6 +104,7 @@ export const featureMetadataSchema = joi
|
|||||||
.unique((a, b) => a.name === b.name)
|
.unique((a, b) => a.name === b.name)
|
||||||
.optional()
|
.optional()
|
||||||
.items(variantsSchema),
|
.items(variantsSchema),
|
||||||
|
createdByUserId: joi.number(),
|
||||||
})
|
})
|
||||||
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
.options({ allowUnknown: false, stripUnknown: true, abortEarly: false });
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ async function setupV3VariantsCompatibilityScenario(
|
|||||||
const stores = createStores();
|
const stores = createStores();
|
||||||
await stores.featureToggleStore.create('some-project', {
|
await stores.featureToggleStore.create('some-project', {
|
||||||
name: 'Feature-with-variants',
|
name: 'Feature-with-variants',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
let sortOrder = 1;
|
let sortOrder = 1;
|
||||||
envs.forEach(async (env) => {
|
envs.forEach(async (env) => {
|
||||||
@ -112,6 +113,7 @@ test('should not import an existing feature', async () => {
|
|||||||
name: 'new-feature',
|
name: 'new-feature',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
strategies: [{ name: 'default' }],
|
strategies: [{ name: 'default' }],
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -137,6 +139,7 @@ test('should not keep existing feature if drop-before-import', async () => {
|
|||||||
name: 'new-feature',
|
name: 'new-feature',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
strategies: [{ name: 'default' }],
|
strategies: [{ name: 'default' }],
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -289,6 +292,7 @@ test('should export featureToggles', async () => {
|
|||||||
|
|
||||||
await stores.featureToggleStore.create('default', {
|
await stores.featureToggleStore.create('default', {
|
||||||
name: 'a-feature',
|
name: 'a-feature',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await stateService.export({ includeFeatureToggles: true });
|
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', {
|
await stores.featureToggleStore.create('default', {
|
||||||
name: 'a-feature',
|
name: 'a-feature',
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
const data = await stateService.export({ includeFeatureToggles: true });
|
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', {
|
await stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
archived: true,
|
archived: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await stores.featureStrategiesStore.createStrategyFeatureEnv({
|
await stores.featureStrategiesStore.createStrategyFeatureEnv({
|
||||||
@ -334,6 +340,7 @@ test('featureStrategy connected to a feature should be included', async () => {
|
|||||||
const featureName = 'fstrat-feature';
|
const featureName = 'fstrat-feature';
|
||||||
await stores.featureToggleStore.create('default', {
|
await stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await stores.featureStrategiesStore.createStrategyFeatureEnv({
|
await stores.featureStrategiesStore.createStrategyFeatureEnv({
|
||||||
@ -662,6 +669,7 @@ test('exporting to new format works', async () => {
|
|||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('fancy', {
|
await stores.featureToggleStore.create('fancy', {
|
||||||
name: 'Some-feature',
|
name: 'Some-feature',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.strategyStore.createStrategy({
|
await stores.strategyStore.createStrategy({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
@ -724,6 +732,7 @@ test('featureStrategies can keep existing', async () => {
|
|||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('fancy', {
|
await stores.featureToggleStore.create('fancy', {
|
||||||
name: 'Some-feature',
|
name: 'Some-feature',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.strategyStore.createStrategy({
|
await stores.strategyStore.createStrategy({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
@ -779,6 +788,7 @@ test('featureStrategies should not keep existing if dropBeforeImport', async ()
|
|||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('fancy', {
|
await stores.featureToggleStore.create('fancy', {
|
||||||
name: 'Some-feature',
|
name: 'Some-feature',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.strategyStore.createStrategy({
|
await stores.strategyStore.createStrategy({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
|
|||||||
@ -396,7 +396,10 @@ export default class StateService {
|
|||||||
.filter(filterExisting(keepExisting, oldToggles))
|
.filter(filterExisting(keepExisting, oldToggles))
|
||||||
.filter(filterEqual(oldToggles))
|
.filter(filterEqual(oldToggles))
|
||||||
.map(async (feature) => {
|
.map(async (feature) => {
|
||||||
await this.toggleStore.create(feature.project, feature);
|
await this.toggleStore.create(feature.project, {
|
||||||
|
createdByUserId: userId,
|
||||||
|
...feature,
|
||||||
|
});
|
||||||
await this.featureEnvironmentStore.connectFeatureToEnvironmentsForProject(
|
await this.featureEnvironmentStore.connectFeatureToEnvironmentsForProject(
|
||||||
feature.name,
|
feature.name,
|
||||||
feature.project,
|
feature.project,
|
||||||
|
|||||||
@ -181,7 +181,10 @@ test('counts toggles', async () => {
|
|||||||
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
|
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('project', { name: uuidv4() });
|
await stores.featureToggleStore.create('project', {
|
||||||
|
name: uuidv4(),
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
await stores.strategyStore.createStrategy({
|
await stores.strategyStore.createStrategy({
|
||||||
name: uuidv4(),
|
name: uuidv4(),
|
||||||
editable: true,
|
editable: true,
|
||||||
@ -237,7 +240,10 @@ test('counts custom strategies', async () => {
|
|||||||
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
|
await stores.settingStore.insert('unleash.enterprise.auth.oidc', {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('project', { name: toggleName });
|
await stores.featureToggleStore.create('project', {
|
||||||
|
name: toggleName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
await stores.strategyStore.createStrategy({
|
await stores.strategyStore.createStrategy({
|
||||||
name: strategyName,
|
name: strategyName,
|
||||||
editable: true,
|
editable: true,
|
||||||
|
|||||||
@ -59,6 +59,7 @@ export interface FeatureToggleDTO {
|
|||||||
createdAt?: Date;
|
createdAt?: Date;
|
||||||
impressionData?: boolean;
|
impressionData?: boolean;
|
||||||
variants?: IVariant[];
|
variants?: IVariant[];
|
||||||
|
createdByUserId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FeatureToggle extends FeatureToggleDTO {
|
export interface FeatureToggle extends FeatureToggleDTO {
|
||||||
|
|||||||
@ -20,7 +20,10 @@ afterAll(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return instance statistics', async () => {
|
test('should return instance statistics', async () => {
|
||||||
stores.featureToggleStore.create('default', { name: 'TestStats1' });
|
stores.featureToggleStore.create('default', {
|
||||||
|
name: 'TestStats1',
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
|
||||||
return app.request
|
return app.request
|
||||||
.get('/api/admin/instance-admin/statistics')
|
.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 () => {
|
test('should return instance statistics as CVS', async () => {
|
||||||
stores.featureToggleStore.create('default', { name: 'TestStats2' });
|
stores.featureToggleStore.create('default', {
|
||||||
stores.featureToggleStore.create('default', { name: 'TestStats3' });
|
name: 'TestStats2',
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
stores.featureToggleStore.create('default', {
|
||||||
|
name: 'TestStats3',
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
|
||||||
const res = await app.request
|
const res = await app.request
|
||||||
.get('/api/admin/instance-admin/statistics/csv')
|
.get('/api/admin/instance-admin/statistics/csv')
|
||||||
|
|||||||
@ -37,7 +37,10 @@ afterAll(async () => {
|
|||||||
test('Can get variants for a feature', async () => {
|
test('Can get variants for a feature', async () => {
|
||||||
const featureName = 'feature-variants';
|
const featureName = 'feature-variants';
|
||||||
const variantName = 'fancy-variant';
|
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(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
'default',
|
'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', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
@ -151,6 +155,7 @@ test('Can patch variants for a feature patches all environments independently',
|
|||||||
|
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
@ -237,6 +242,7 @@ test('Can push variants to multiple environments', async () => {
|
|||||||
});
|
});
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
@ -339,6 +345,7 @@ test('Can add variant for a feature', async () => {
|
|||||||
|
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
@ -394,6 +401,7 @@ test('Can remove variant for a feature', async () => {
|
|||||||
|
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
@ -438,6 +446,7 @@ test('PUT overwrites current variant on feature', async () => {
|
|||||||
];
|
];
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
@ -492,6 +501,7 @@ test('PUTing an invalid variant throws 400 exception', async () => {
|
|||||||
const featureName = 'variants-validation-feature';
|
const featureName = 'variants-validation-feature';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
const invalidJson = [
|
const invalidJson = [
|
||||||
@ -518,6 +528,7 @@ test('Invalid variant in PATCH also throws 400 exception', async () => {
|
|||||||
const featureName = 'patch-validation-feature';
|
const featureName = 'patch-validation-feature';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
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';
|
const featureName = 'variants-validation-with-all-variable-weights';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-validation-with-no-variable-weights';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
featureName,
|
featureName,
|
||||||
@ -681,6 +694,7 @@ test('Patching with a fixed variant and variable variants splits remaining weigh
|
|||||||
const featureName = 'variants-fixed-and-variable';
|
const featureName = 'variants-fixed-and-variable';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-multiple-fixed-and-variable';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-fixed-weight-over-1000';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-fixed-weight-equals-1000-no-variable-weight';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
@ -944,6 +961,7 @@ test('PATCH endpoint validates uniqueness of variant names', async () => {
|
|||||||
];
|
];
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
@ -989,6 +1007,7 @@ test('PUT endpoint validates uniqueness of variant names', async () => {
|
|||||||
const featureName = 'variants-put-uniqueness-names';
|
const featureName = 'variants-put-uniqueness-names';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-sort-by-name';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
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';
|
const featureName = 'variants-patch-sort-by-name';
|
||||||
await db.stores.featureToggleStore.create('default', {
|
await db.stores.featureToggleStore.create('default', {
|
||||||
name: featureName,
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||||
|
|||||||
@ -118,6 +118,7 @@ export const seedDatabaseForPlaygroundTest = async (
|
|||||||
...feature,
|
...feature,
|
||||||
createdAt: undefined,
|
createdAt: undefined,
|
||||||
variants: null,
|
variants: null,
|
||||||
|
createdByUserId: 9999,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -52,11 +52,13 @@ test('Project with no stale toggles should have 100% health rating', async () =>
|
|||||||
name: 'health-rating-not-stale',
|
name: 'health-rating-not-stale',
|
||||||
description: 'new',
|
description: 'new',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating', {
|
await stores.featureToggleStore.create('health-rating', {
|
||||||
name: 'health-rating-not-stale-2',
|
name: 'health-rating-not-stale-2',
|
||||||
description: 'new too',
|
description: 'new too',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
const rating =
|
const rating =
|
||||||
await projectHealthService.calculateHealthRating(savedProject);
|
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',
|
name: 'health-rating-2-not-stale',
|
||||||
description: 'new',
|
description: 'new',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating-2', {
|
await stores.featureToggleStore.create('health-rating-2', {
|
||||||
name: 'health-rating-2-not-stale-2',
|
name: 'health-rating-2-not-stale-2',
|
||||||
description: 'new too',
|
description: 'new too',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating-2', {
|
await stores.featureToggleStore.create('health-rating-2', {
|
||||||
name: 'health-rating-2-stale-1',
|
name: 'health-rating-2-stale-1',
|
||||||
description: 'stale',
|
description: 'stale',
|
||||||
stale: true,
|
stale: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating-2', {
|
await stores.featureToggleStore.create('health-rating-2', {
|
||||||
name: 'health-rating-2-stale-2',
|
name: 'health-rating-2-stale-2',
|
||||||
description: 'stale too',
|
description: 'stale too',
|
||||||
stale: true,
|
stale: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
const rating =
|
const rating =
|
||||||
await projectHealthService.calculateHealthRating(savedProject);
|
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',
|
name: 'health-rating-3-not-stale',
|
||||||
description: 'new',
|
description: 'new',
|
||||||
stale: false,
|
stale: false,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating-3', {
|
await stores.featureToggleStore.create('health-rating-3', {
|
||||||
name: 'health-rating-3-potentially-stale',
|
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',
|
type: 'release',
|
||||||
stale: false,
|
stale: false,
|
||||||
createdAt: new Date(Date.UTC(2020, 1, 1)),
|
createdAt: new Date(Date.UTC(2020, 1, 1)),
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create('health-rating-3', {
|
await stores.featureToggleStore.create('health-rating-3', {
|
||||||
name: 'health-rating-3-stale',
|
name: 'health-rating-3-stale',
|
||||||
description: 'stale',
|
description: 'stale',
|
||||||
stale: true,
|
stale: true,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
const rating =
|
const rating =
|
||||||
await projectHealthService.calculateHealthRating(savedProject);
|
await projectHealthService.calculateHealthRating(savedProject);
|
||||||
|
|||||||
@ -177,6 +177,7 @@ test('should not be able to delete project with toggles', async () => {
|
|||||||
await projectService.createProject(project, user);
|
await projectService.createProject(project, user);
|
||||||
await stores.featureToggleStore.create(project.id, {
|
await stores.featureToggleStore.create(project.id, {
|
||||||
name: 'test-project-delete',
|
name: 'test-project-delete',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1461,9 +1462,11 @@ test('should only count active feature toggles for project', async () => {
|
|||||||
|
|
||||||
await stores.featureToggleStore.create(project.id, {
|
await stores.featureToggleStore.create(project.id, {
|
||||||
name: 'only-active-t1',
|
name: 'only-active-t1',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await stores.featureToggleStore.create(project.id, {
|
await stores.featureToggleStore.create(project.id, {
|
||||||
name: 'only-active-t2',
|
name: 'only-active-t2',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await featureToggleService.archiveToggle('only-active-t2', user);
|
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, {
|
await stores.featureToggleStore.create(project.id, {
|
||||||
name: 'archived-toggle',
|
name: 'archived-toggle',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await featureToggleService.archiveToggle('archived-toggle', user);
|
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, {
|
await stores.featureToggleStore.create(project.id, {
|
||||||
name: toggleName,
|
name: toggleName,
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
|
|
||||||
await stores.featureToggleStore.archive(toggleName);
|
await stores.featureToggleStore.archive(toggleName);
|
||||||
|
|||||||
@ -31,7 +31,10 @@ test('Setting enabled to same as existing value returns 0', async () => {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
});
|
});
|
||||||
await featureStore.create('default', { name: featureName });
|
await featureStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
await featureEnvironmentStore.connectProject(envName, 'default');
|
await featureEnvironmentStore.connectProject(envName, 'default');
|
||||||
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
||||||
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(
|
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(
|
||||||
@ -54,7 +57,10 @@ test('Setting enabled to not existing value returns 1', async () => {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
type: 'test',
|
type: 'test',
|
||||||
});
|
});
|
||||||
await featureStore.create('default', { name: featureName });
|
await featureStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
await featureEnvironmentStore.connectProject(envName, 'default');
|
await featureEnvironmentStore.connectProject(envName, 'default');
|
||||||
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
||||||
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(
|
const enabledStatus = await featureEnvironmentStore.isEnvironmentEnabled(
|
||||||
|
|||||||
@ -19,7 +19,10 @@ beforeAll(async () => {
|
|||||||
featureTagStore = stores.featureTagStore;
|
featureTagStore = stores.featureTagStore;
|
||||||
featureToggleStore = stores.featureToggleStore;
|
featureToggleStore = stores.featureToggleStore;
|
||||||
await stores.tagStore.createTag(tag);
|
await stores.tagStore.createTag(tag);
|
||||||
await featureToggleStore.create('default', { name: featureName });
|
await featureToggleStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -80,6 +83,7 @@ test('get all feature tags', async () => {
|
|||||||
await featureTagStore.tagFeature(featureName, tag, TESTUSERID);
|
await featureTagStore.tagFeature(featureName, tag, TESTUSERID);
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'some-other-toggle',
|
name: 'some-other-toggle',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await featureTagStore.tagFeature('some-other-toggle', tag, TESTUSERID);
|
await featureTagStore.tagFeature('some-other-toggle', tag, TESTUSERID);
|
||||||
const all = await featureTagStore.getAll();
|
const all = await featureTagStore.getAll();
|
||||||
@ -89,6 +93,7 @@ test('get all feature tags', async () => {
|
|||||||
test('should import feature tags', async () => {
|
test('should import feature tags', async () => {
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'some-other-toggle-import',
|
name: 'some-other-toggle-import',
|
||||||
|
createdByUserId: 9999,
|
||||||
});
|
});
|
||||||
await featureTagStore.tagFeatures([
|
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 () => {
|
test('Returns empty tag list for existing feature with no tags', async () => {
|
||||||
const name = 'feature.with.no.tags';
|
const name = 'feature.with.no.tags';
|
||||||
await featureToggleStore.create('default', { name });
|
await featureToggleStore.create('default', { name, createdByUserId: 9999 });
|
||||||
const tags = await featureTagStore.getAllTagsForFeature(name);
|
const tags = await featureTagStore.getAllTagsForFeature(name);
|
||||||
expect(tags).toHaveLength(0);
|
expect(tags).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user