mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-18 11:14:57 +02:00
test: project insights service test (#6661)
This commit is contained in:
parent
f5a7cc9125
commit
86f229a69d
@ -323,10 +323,26 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeatureTypeCounts(
|
async getFeatureTypeCounts(
|
||||||
params: IFeatureProjectUserParams,
|
params: IFeatureProjectUserParams,
|
||||||
): Promise<IFeatureTypeCount[]> {
|
): Promise<IFeatureTypeCount[]> {
|
||||||
throw new Error('Method not implemented.');
|
const typeCounts = this.features.reduce(
|
||||||
|
(acc, feature) => {
|
||||||
|
if (!feature.type) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[feature.type]) {
|
||||||
|
acc[feature.type] = { type: feature.type, count: 0 };
|
||||||
|
}
|
||||||
|
acc[feature.type].count += 1;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, IFeatureTypeCount>,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Object.values(typeCounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCreatedByUserId(batchSize: number): Promise<number | undefined> {
|
setCreatedByUserId(batchSize: number): Promise<number | undefined> {
|
||||||
|
@ -53,17 +53,14 @@ export const createProjectInsightsService = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createFakeProjectInsightsService = (
|
export const createFakeProjectInsightsService = () => {
|
||||||
config: IUnleashConfig,
|
|
||||||
): ProjectInsightsService => {
|
|
||||||
const projectStore = new FakeProjectStore();
|
const projectStore = new FakeProjectStore();
|
||||||
const featureToggleStore = new FakeFeatureToggleStore();
|
const featureToggleStore = new FakeFeatureToggleStore();
|
||||||
const featureTypeStore = new FakeFeatureTypeStore();
|
const featureTypeStore = new FakeFeatureTypeStore();
|
||||||
const projectStatsStore = new FakeProjectStatsStore();
|
const projectStatsStore = new FakeProjectStatsStore();
|
||||||
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
const featureStrategiesStore = new FakeFeatureStrategiesStore();
|
||||||
const projectInsightsReadModel = new FakeProjectInsightsReadModel();
|
const projectInsightsReadModel = new FakeProjectInsightsReadModel();
|
||||||
|
const projectInsightsService = new ProjectInsightsService(
|
||||||
return new ProjectInsightsService(
|
|
||||||
{
|
{
|
||||||
projectStore,
|
projectStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
@ -73,4 +70,12 @@ export const createFakeProjectInsightsService = (
|
|||||||
},
|
},
|
||||||
projectInsightsReadModel,
|
projectInsightsReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
projectInsightsService,
|
||||||
|
projectStatsStore,
|
||||||
|
featureToggleStore,
|
||||||
|
projectStore,
|
||||||
|
projectInsightsReadModel,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -8,12 +8,18 @@ const changeRequestCounts: ChangeRequestCounts = {
|
|||||||
approved: 0,
|
approved: 0,
|
||||||
applied: 0,
|
applied: 0,
|
||||||
rejected: 0,
|
rejected: 0,
|
||||||
reviewRequired: 10,
|
reviewRequired: 0,
|
||||||
scheduled: 0,
|
scheduled: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FakeProjectInsightsReadModel implements IProjectInsightsReadModel {
|
export class FakeProjectInsightsReadModel implements IProjectInsightsReadModel {
|
||||||
|
private counts: Record<string, ChangeRequestCounts> = {};
|
||||||
|
|
||||||
async getChangeRequests(projectId: string): Promise<ChangeRequestCounts> {
|
async getChangeRequests(projectId: string): Promise<ChangeRequestCounts> {
|
||||||
return changeRequestCounts;
|
return this.counts[projectId] ?? changeRequestCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setChangeRequests(projectId: string, counts: ChangeRequestCounts) {
|
||||||
|
this.counts[projectId] = counts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,296 @@
|
|||||||
|
import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
|
||||||
|
import getLogger from '../../../test/fixtures/no-logger';
|
||||||
|
import type FeatureToggleService from '../../../lib/features/feature-toggle/feature-toggle-service';
|
||||||
|
import type ProjectService from '../../../lib/features/project/project-service';
|
||||||
|
import { createTestConfig } from '../../../test/config/test-config';
|
||||||
|
import {
|
||||||
|
EventService,
|
||||||
|
type ProjectInsightsService,
|
||||||
|
} from '../../../lib/services';
|
||||||
|
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
||||||
|
import { subDays } from 'date-fns';
|
||||||
|
import {
|
||||||
|
createFeatureToggleService,
|
||||||
|
createProjectService,
|
||||||
|
} from '../../../lib/features';
|
||||||
|
import type { IUnleashStores, IUser } from '../../../lib/types';
|
||||||
|
import type { User } from '../../../lib/server-impl';
|
||||||
|
import { createProjectInsightsService } from './createProjectInsightsService';
|
||||||
|
|
||||||
|
let stores: IUnleashStores;
|
||||||
|
let db: ITestDb;
|
||||||
|
|
||||||
|
let projectService: ProjectService;
|
||||||
|
let projectInsightsService: ProjectInsightsService;
|
||||||
|
let eventService: EventService;
|
||||||
|
let featureToggleService: FeatureToggleService;
|
||||||
|
let user: User; // many methods in this test use User instead of IUser
|
||||||
|
let opsUser: IUser;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
db = await dbInit('project_service_serial', getLogger);
|
||||||
|
stores = db.stores;
|
||||||
|
// @ts-ignore return type IUser type missing generateImageUrl
|
||||||
|
user = await stores.userStore.insert({
|
||||||
|
name: 'Some Name',
|
||||||
|
email: 'test@getunleash.io',
|
||||||
|
});
|
||||||
|
opsUser = await stores.userStore.insert({
|
||||||
|
name: 'Test user',
|
||||||
|
email: 'test@example.com',
|
||||||
|
});
|
||||||
|
const config = createTestConfig({
|
||||||
|
getLogger,
|
||||||
|
});
|
||||||
|
eventService = new EventService(stores, config);
|
||||||
|
|
||||||
|
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||||
|
|
||||||
|
projectService = createProjectService(db.rawDatabase, config);
|
||||||
|
|
||||||
|
projectInsightsService = createProjectInsightsService(
|
||||||
|
db.rawDatabase,
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await db.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await stores.eventStore.deleteAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateFeature = async (featureName: string, update: any) => {
|
||||||
|
return db.rawDatabase
|
||||||
|
.table('features')
|
||||||
|
.update(update)
|
||||||
|
.where({ name: featureName });
|
||||||
|
};
|
||||||
|
|
||||||
|
test('should return average time to production per toggle', async () => {
|
||||||
|
const project = {
|
||||||
|
id: 'average-time-to-prod-per-toggle',
|
||||||
|
name: 'average-time-to-prod-per-toggle',
|
||||||
|
mode: 'open' as const,
|
||||||
|
defaultStickiness: 'clientId',
|
||||||
|
};
|
||||||
|
|
||||||
|
await projectService.createProject(project, user);
|
||||||
|
|
||||||
|
const toggles = [
|
||||||
|
{ name: 'average-prod-time-pt', subdays: 7 },
|
||||||
|
{ name: 'average-prod-time-pt-2', subdays: 14 },
|
||||||
|
{ name: 'average-prod-time-pt-3', subdays: 40 },
|
||||||
|
{ name: 'average-prod-time-pt-4', subdays: 15 },
|
||||||
|
{ name: 'average-prod-time-pt-5', subdays: 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const featureToggles = await Promise.all(
|
||||||
|
toggles.map((toggle) => {
|
||||||
|
return featureToggleService.createFeatureToggle(
|
||||||
|
project.id,
|
||||||
|
toggle,
|
||||||
|
user.email,
|
||||||
|
opsUser.id,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
featureToggles.map((toggle) => {
|
||||||
|
return eventService.storeEvent(
|
||||||
|
new FeatureEnvironmentEvent({
|
||||||
|
enabled: true,
|
||||||
|
project: project.id,
|
||||||
|
featureName: toggle.name,
|
||||||
|
environment: 'default',
|
||||||
|
createdBy: 'Fredrik',
|
||||||
|
createdByUserId: opsUser.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
toggles.map((toggle) =>
|
||||||
|
updateFeature(toggle.name, {
|
||||||
|
created_at: subDays(new Date(), toggle.subdays),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await projectInsightsService.getDoraMetrics(project.id);
|
||||||
|
|
||||||
|
expect(result.features).toHaveLength(5);
|
||||||
|
expect(result.features[0].timeToProduction).toBeTruthy();
|
||||||
|
expect(result.projectAverage).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return average time to production per toggle for a specific project', async () => {
|
||||||
|
const project1 = {
|
||||||
|
id: 'average-time-to-prod-per-toggle-1',
|
||||||
|
name: 'Project 1',
|
||||||
|
mode: 'open' as const,
|
||||||
|
defaultStickiness: 'clientId',
|
||||||
|
};
|
||||||
|
|
||||||
|
const project2 = {
|
||||||
|
id: 'average-time-to-prod-per-toggle-2',
|
||||||
|
name: 'Project 2',
|
||||||
|
mode: 'open' as const,
|
||||||
|
defaultStickiness: 'clientId',
|
||||||
|
};
|
||||||
|
|
||||||
|
await projectService.createProject(project1, user);
|
||||||
|
await projectService.createProject(project2, user);
|
||||||
|
|
||||||
|
const togglesProject1 = [
|
||||||
|
{ name: 'average-prod-time-pt-10', subdays: 7 },
|
||||||
|
{ name: 'average-prod-time-pt-11', subdays: 14 },
|
||||||
|
{ name: 'average-prod-time-pt-12', subdays: 40 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const togglesProject2 = [
|
||||||
|
{ name: 'average-prod-time-pt-13', subdays: 15 },
|
||||||
|
{ name: 'average-prod-time-pt-14', subdays: 2 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const featureTogglesProject1 = await Promise.all(
|
||||||
|
togglesProject1.map((toggle) => {
|
||||||
|
return featureToggleService.createFeatureToggle(
|
||||||
|
project1.id,
|
||||||
|
toggle,
|
||||||
|
user.email,
|
||||||
|
opsUser.id,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const featureTogglesProject2 = await Promise.all(
|
||||||
|
togglesProject2.map((toggle) => {
|
||||||
|
return featureToggleService.createFeatureToggle(
|
||||||
|
project2.id,
|
||||||
|
toggle,
|
||||||
|
user.email,
|
||||||
|
opsUser.id,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
featureTogglesProject1.map((toggle) => {
|
||||||
|
return eventService.storeEvent(
|
||||||
|
new FeatureEnvironmentEvent({
|
||||||
|
enabled: true,
|
||||||
|
project: project1.id,
|
||||||
|
featureName: toggle.name,
|
||||||
|
environment: 'default',
|
||||||
|
createdBy: 'Fredrik',
|
||||||
|
createdByUserId: opsUser.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
featureTogglesProject2.map((toggle) => {
|
||||||
|
return eventService.storeEvent(
|
||||||
|
new FeatureEnvironmentEvent({
|
||||||
|
enabled: true,
|
||||||
|
project: project2.id,
|
||||||
|
featureName: toggle.name,
|
||||||
|
environment: 'default',
|
||||||
|
createdBy: 'Fredrik',
|
||||||
|
createdByUserId: opsUser.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
togglesProject1.map((toggle) =>
|
||||||
|
updateFeature(toggle.name, {
|
||||||
|
created_at: subDays(new Date(), toggle.subdays),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
togglesProject2.map((toggle) =>
|
||||||
|
updateFeature(toggle.name, {
|
||||||
|
created_at: subDays(new Date(), toggle.subdays),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultProject1 = await projectInsightsService.getDoraMetrics(
|
||||||
|
project1.id,
|
||||||
|
);
|
||||||
|
const resultProject2 = await projectInsightsService.getDoraMetrics(
|
||||||
|
project2.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(resultProject1.features).toHaveLength(3);
|
||||||
|
expect(resultProject2.features).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return average time to production per toggle and include archived toggles', async () => {
|
||||||
|
const project1 = {
|
||||||
|
id: 'average-time-to-prod-per-toggle-12',
|
||||||
|
name: 'Project 1',
|
||||||
|
mode: 'open' as const,
|
||||||
|
defaultStickiness: 'clientId',
|
||||||
|
};
|
||||||
|
|
||||||
|
await projectService.createProject(project1, user);
|
||||||
|
|
||||||
|
const togglesProject1 = [
|
||||||
|
{ name: 'average-prod-time-pta-10', subdays: 7 },
|
||||||
|
{ name: 'average-prod-time-pta-11', subdays: 14 },
|
||||||
|
{ name: 'average-prod-time-pta-12', subdays: 40 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const featureTogglesProject1 = await Promise.all(
|
||||||
|
togglesProject1.map((toggle) => {
|
||||||
|
return featureToggleService.createFeatureToggle(
|
||||||
|
project1.id,
|
||||||
|
toggle,
|
||||||
|
user.email,
|
||||||
|
opsUser.id,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
featureTogglesProject1.map((toggle) => {
|
||||||
|
return eventService.storeEvent(
|
||||||
|
new FeatureEnvironmentEvent({
|
||||||
|
enabled: true,
|
||||||
|
project: project1.id,
|
||||||
|
featureName: toggle.name,
|
||||||
|
environment: 'default',
|
||||||
|
createdBy: 'Fredrik',
|
||||||
|
createdByUserId: opsUser.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
togglesProject1.map((toggle) =>
|
||||||
|
updateFeature(toggle.name, {
|
||||||
|
created_at: subDays(new Date(), toggle.subdays),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await featureToggleService.archiveToggle('average-prod-time-pta-12', user);
|
||||||
|
|
||||||
|
const resultProject1 = await projectInsightsService.getDoraMetrics(
|
||||||
|
project1.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(resultProject1.features).toHaveLength(3);
|
||||||
|
});
|
@ -0,0 +1,70 @@
|
|||||||
|
import { createFakeProjectInsightsService } from './createProjectInsightsService';
|
||||||
|
|
||||||
|
test('Return basic insights', async () => {
|
||||||
|
const {
|
||||||
|
projectInsightsService,
|
||||||
|
projectStatsStore,
|
||||||
|
featureToggleStore,
|
||||||
|
projectStore,
|
||||||
|
projectInsightsReadModel,
|
||||||
|
} = createFakeProjectInsightsService();
|
||||||
|
await featureToggleStore.create('default', {
|
||||||
|
name: 'irrelevant',
|
||||||
|
createdByUserId: 1,
|
||||||
|
type: 'release',
|
||||||
|
});
|
||||||
|
await projectInsightsReadModel.setChangeRequests('default', {
|
||||||
|
total: 5,
|
||||||
|
approved: 1,
|
||||||
|
applied: 1,
|
||||||
|
rejected: 1,
|
||||||
|
reviewRequired: 1,
|
||||||
|
scheduled: 1,
|
||||||
|
});
|
||||||
|
await projectStore.create({
|
||||||
|
id: 'default',
|
||||||
|
name: 'irrelevant',
|
||||||
|
});
|
||||||
|
await projectStatsStore.updateProjectStats('default', {
|
||||||
|
archivedCurrentWindow: 1,
|
||||||
|
archivedPastWindow: 1,
|
||||||
|
createdCurrentWindow: 1,
|
||||||
|
createdPastWindow: 1,
|
||||||
|
avgTimeToProdCurrentWindow: 1,
|
||||||
|
projectActivityCurrentWindow: 1,
|
||||||
|
projectActivityPastWindow: 1,
|
||||||
|
projectMembersAddedCurrentWindow: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const insights = await projectInsightsService.getProjectInsights('default');
|
||||||
|
|
||||||
|
expect(insights).toEqual({
|
||||||
|
stats: {
|
||||||
|
archivedCurrentWindow: 1,
|
||||||
|
archivedPastWindow: 1,
|
||||||
|
createdCurrentWindow: 1,
|
||||||
|
createdPastWindow: 1,
|
||||||
|
avgTimeToProdCurrentWindow: 1,
|
||||||
|
projectActivityCurrentWindow: 1,
|
||||||
|
projectActivityPastWindow: 1,
|
||||||
|
projectMembersAddedCurrentWindow: 1,
|
||||||
|
},
|
||||||
|
featureTypeCounts: [{ type: 'release', count: 1 }],
|
||||||
|
health: {
|
||||||
|
activeCount: 0,
|
||||||
|
potentiallyStaleCount: 0,
|
||||||
|
staleCount: 0,
|
||||||
|
rating: 100,
|
||||||
|
},
|
||||||
|
leadTime: { features: [], projectAverage: 0 },
|
||||||
|
changeRequests: {
|
||||||
|
total: 5,
|
||||||
|
approved: 1,
|
||||||
|
applied: 1,
|
||||||
|
rejected: 1,
|
||||||
|
reviewRequired: 1,
|
||||||
|
scheduled: 1,
|
||||||
|
},
|
||||||
|
members: { currentMembers: 0, change: 0 },
|
||||||
|
});
|
||||||
|
});
|
@ -54,9 +54,7 @@ export class ProjectInsightsService {
|
|||||||
this.projectInsightsReadModel = projectInsightsReadModel;
|
this.projectInsightsReadModel = projectInsightsReadModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getDoraMetrics(
|
async getDoraMetrics(projectId: string): Promise<ProjectDoraMetricsSchema> {
|
||||||
projectId: string,
|
|
||||||
): Promise<ProjectDoraMetricsSchema> {
|
|
||||||
const activeFeatureToggles = (
|
const activeFeatureToggles = (
|
||||||
await this.featureToggleStore.getAll({ project: projectId })
|
await this.featureToggleStore.getAll({ project: projectId })
|
||||||
).map((feature) => feature.name);
|
).map((feature) => feature.name);
|
||||||
|
@ -118,6 +118,7 @@ export default class ProjectController extends Controller {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @deprecated use project insights instead */
|
||||||
this.route({
|
this.route({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: '/:projectId/dora',
|
path: '/:projectId/dora',
|
||||||
@ -245,6 +246,7 @@ export default class ProjectController extends Controller {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated use projectInsights instead */
|
||||||
async getProjectDora(
|
async getProjectDora(
|
||||||
req: IAuthRequest,
|
req: IAuthRequest,
|
||||||
res: Response<ProjectDoraMetricsSchema>,
|
res: Response<ProjectDoraMetricsSchema>,
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
import dbInit, { type ITestDb } from '../helpers/database-init';
|
import dbInit, { type ITestDb } from '../../../test/e2e/helpers/database-init';
|
||||||
import getLogger from '../../fixtures/no-logger';
|
import getLogger from '../../../test/fixtures/no-logger';
|
||||||
import type FeatureToggleService from '../../../lib/features/feature-toggle/feature-toggle-service';
|
import type FeatureToggleService from '../feature-toggle/feature-toggle-service';
|
||||||
import type ProjectService from '../../../lib/features/project/project-service';
|
import type ProjectService from './project-service';
|
||||||
import type { AccessService } from '../../../lib/services/access-service';
|
import type { AccessService } from '../../services/access-service';
|
||||||
import { MOVE_FEATURE_TOGGLE } from '../../../lib/types/permissions';
|
import { MOVE_FEATURE_TOGGLE } from '../../types/permissions';
|
||||||
import { createTestConfig } from '../../config/test-config';
|
import { createTestConfig } from '../../../test/config/test-config';
|
||||||
import { RoleName } from '../../../lib/types/model';
|
import { RoleName } from '../../types/model';
|
||||||
import { randomId } from '../../../lib/util/random-id';
|
import { randomId } from '../../util/random-id';
|
||||||
import EnvironmentService from '../../../lib/features/project-environments/environment-service';
|
import EnvironmentService from '../project-environments/environment-service';
|
||||||
import IncompatibleProjectError from '../../../lib/error/incompatible-project-error';
|
import IncompatibleProjectError from '../../error/incompatible-project-error';
|
||||||
import { EventService } from '../../../lib/services';
|
import { EventService } from '../../services';
|
||||||
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
import { FeatureEnvironmentEvent } from '../../types/events';
|
||||||
import { addDays, subDays } from 'date-fns';
|
import { addDays, subDays } from 'date-fns';
|
||||||
import {
|
import {
|
||||||
createAccessService,
|
createAccessService,
|
||||||
createFeatureToggleService,
|
createFeatureToggleService,
|
||||||
createProjectService,
|
createProjectService,
|
||||||
} from '../../../lib/features';
|
} from '../index';
|
||||||
import {
|
import {
|
||||||
type IGroup,
|
type IGroup,
|
||||||
type IUnleashStores,
|
type IUnleashStores,
|
||||||
type IUser,
|
type IUser,
|
||||||
SYSTEM_USER,
|
SYSTEM_USER,
|
||||||
SYSTEM_USER_ID,
|
SYSTEM_USER_ID,
|
||||||
} from '../../../lib/types';
|
} from '../../types';
|
||||||
import type { User } from '../../../lib/server-impl';
|
import type { User } from '../../server-impl';
|
||||||
import { InvalidOperationError } from '../../../lib/error';
|
import { InvalidOperationError } from '../../error';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
@ -945,6 +945,7 @@ export default class ProjectService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated use projectInsightsService instead */
|
||||||
async getDoraMetrics(projectId: string): Promise<ProjectDoraMetricsSchema> {
|
async getDoraMetrics(projectId: string): Promise<ProjectDoraMetricsSchema> {
|
||||||
const activeFeatureToggles = (
|
const activeFeatureToggles = (
|
||||||
await this.featureToggleStore.getAll({ project: projectId })
|
await this.featureToggleStore.getAll({ project: projectId })
|
||||||
|
@ -270,7 +270,7 @@ export const createServices = (
|
|||||||
: createFakeProjectService(config);
|
: createFakeProjectService(config);
|
||||||
const projectInsightsService = db
|
const projectInsightsService = db
|
||||||
? createProjectInsightsService(db, config)
|
? createProjectInsightsService(db, config)
|
||||||
: createFakeProjectInsightsService(config);
|
: createFakeProjectInsightsService().projectInsightsService;
|
||||||
|
|
||||||
const projectHealthService = new ProjectHealthService(
|
const projectHealthService = new ProjectHealthService(
|
||||||
stores,
|
stores,
|
||||||
|
21
src/test/fixtures/fake-project-stats-store.ts
vendored
21
src/test/fixtures/fake-project-stats-store.ts
vendored
@ -3,25 +3,28 @@ import type {
|
|||||||
ICreateEnabledDates,
|
ICreateEnabledDates,
|
||||||
IProjectStatsStore,
|
IProjectStatsStore,
|
||||||
} from '../../lib/types/stores/project-stats-store-type';
|
} from '../../lib/types/stores/project-stats-store-type';
|
||||||
|
import type { DoraFeaturesSchema } from '../../lib/openapi';
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
|
||||||
export default class FakeProjectStatsStore implements IProjectStatsStore {
|
export default class FakeProjectStatsStore implements IProjectStatsStore {
|
||||||
updateProjectStats(
|
private stats: Record<string, IProjectStats> = {};
|
||||||
|
|
||||||
|
async updateProjectStats(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
status: IProjectStats,
|
stats: IProjectStats,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
throw new Error('not implemented');
|
this.stats[projectId] = stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
getProjectStats(projectId: string): Promise<IProjectStats> {
|
async getProjectStats(projectId: string): Promise<IProjectStats> {
|
||||||
throw new Error('not implemented');
|
return this.stats[projectId];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTimeToProdDates(): Promise<ICreateEnabledDates[]> {
|
async getTimeToProdDates(): Promise<ICreateEnabledDates[]> {
|
||||||
throw new Error('not implemented');
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTimeToProdDatesForFeatureToggles(): Promise<any> {
|
async getTimeToProdDatesForFeatureToggles(): Promise<DoraFeaturesSchema[]> {
|
||||||
throw new Error('not implemented');
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
src/test/fixtures/fake-project-store.ts
vendored
4
src/test/fixtures/fake-project-store.ts
vendored
@ -166,13 +166,13 @@ export default class FakeProjectStore implements IProjectStore {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
getMembersCountByProjectAfterDate(
|
async getMembersCountByProjectAfterDate(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
projectId: string,
|
projectId: string,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
date: string,
|
date: string,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
throw new Error('Method not implemented');
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDefaultStrategy(
|
updateDefaultStrategy(
|
||||||
|
Loading…
Reference in New Issue
Block a user