diff --git a/src/lib/db/feature-strategy-store.ts b/src/lib/db/feature-strategy-store.ts index 80f56eb00d..8484de0eb0 100644 --- a/src/lib/db/feature-strategy-store.ts +++ b/src/lib/db/feature-strategy-store.ts @@ -409,6 +409,15 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { .where({ project_name: projectId, environment }) .del(); } + + async setProjectForStrategiesBelongingToFeature( + featureName: string, + newProjectId: string, + ): Promise { + await this.db(T.featureStrategies) + .where({ feature_name: featureName }) + .update({ project_name: newProjectId }); + } } module.exports = FeatureStrategiesStore; diff --git a/src/lib/services/feature-toggle-service-v2.ts b/src/lib/services/feature-toggle-service-v2.ts index 0a9d1e64d4..1155f5a40b 100644 --- a/src/lib/services/feature-toggle-service-v2.ts +++ b/src/lib/services/feature-toggle-service-v2.ts @@ -785,6 +785,16 @@ class FeatureToggleServiceV2 { async getProjectId(name: string): Promise { return this.featureToggleStore.getProjectId(name); } + + async updateFeatureStrategyProject( + featureName: string, + newProjectId: string, + ): Promise { + await this.featureStrategiesStore.setProjectForStrategiesBelongingToFeature( + featureName, + newProjectId, + ); + } } module.exports = FeatureToggleServiceV2; diff --git a/src/lib/services/project-service.ts b/src/lib/services/project-service.ts index 0141ce407d..ac8e31a44e 100644 --- a/src/lib/services/project-service.ts +++ b/src/lib/services/project-service.ts @@ -195,6 +195,10 @@ export default class ProjectService { user.username, FEATURE_PROJECT_CHANGE, ); + await this.featureToggleService.updateFeatureStrategyProject( + featureName, + newProjectId, + ); return updatedFeature; } diff --git a/src/lib/types/stores/feature-strategies-store.ts b/src/lib/types/stores/feature-strategies-store.ts index 4191c165d1..85605324ed 100644 --- a/src/lib/types/stores/feature-strategies-store.ts +++ b/src/lib/types/stores/feature-strategies-store.ts @@ -46,4 +46,9 @@ export interface IFeatureStrategiesStore projectId: String, environment: String, ): Promise; + + setProjectForStrategiesBelongingToFeature( + featureName: string, + newProjectId: string, + ): Promise; } diff --git a/src/test/e2e/stores/feature-strategies-store.e2e.test.ts b/src/test/e2e/stores/feature-strategies-store.e2e.test.ts new file mode 100644 index 0000000000..a7be8af2ce --- /dev/null +++ b/src/test/e2e/stores/feature-strategies-store.e2e.test.ts @@ -0,0 +1,72 @@ +import { IFeatureStrategiesStore } from 'lib/types/stores/feature-strategies-store'; +import { IFeatureToggleStore } from 'lib/types/stores/feature-toggle-store'; +import dbInit from '../helpers/database-init'; +import getLogger from '../../fixtures/no-logger'; + +let stores; +let db; +let featureStrategiesStore: IFeatureStrategiesStore; +let featureToggleStore: IFeatureToggleStore; + +const featureName = 'test-strategies-move-project'; + +beforeAll(async () => { + db = await dbInit('feature_strategies_store_serial', getLogger); + stores = db.stores; + featureStrategiesStore = stores.featureStrategiesStore; + featureToggleStore = stores.featureToggleStore; + await featureToggleStore.create('default', { name: featureName }); +}); + +afterAll(async () => { + await db.destroy(); +}); + +test('Can successfully update project for all strategies belonging to feature', async () => { + const newProjectId = 'different-project'; + const oldProjectId = 'default'; + const environment = 'default'; + await featureStrategiesStore.createStrategyFeatureEnv({ + strategyName: 'default', + projectId: oldProjectId, + environment, + featureName, + constraints: [], + parameters: {}, + sortOrder: 15, + }); + await featureStrategiesStore.createStrategyFeatureEnv({ + strategyName: 'default', + projectId: oldProjectId, + environment, + featureName, + constraints: [], + parameters: {}, + sortOrder: 20, + }); + const strats = await featureStrategiesStore.getStrategiesForFeatureEnv( + oldProjectId, + featureName, + environment, + ); + expect(strats).toHaveLength(2); + await featureStrategiesStore.setProjectForStrategiesBelongingToFeature( + featureName, + newProjectId, + ); + const newProjectStrats = + await featureStrategiesStore.getStrategiesForFeatureEnv( + newProjectId, + featureName, + environment, + ); + expect(newProjectStrats).toHaveLength(2); + + const oldProjectStrats = + await featureStrategiesStore.getStrategiesForFeatureEnv( + oldProjectId, + featureName, + environment, + ); + return expect(oldProjectStrats).toHaveLength(0); +}); diff --git a/src/test/fixtures/fake-feature-strategies-store.ts b/src/test/fixtures/fake-feature-strategies-store.ts index 23a07211d6..36941061c3 100644 --- a/src/test/fixtures/fake-feature-strategies-store.ts +++ b/src/test/fixtures/fake-feature-strategies-store.ts @@ -250,6 +250,19 @@ export default class FakeFeatureStrategiesStore return Promise.resolve(enabled); } + async setProjectForStrategiesBelongingToFeature( + featureName: string, + newProjectId: string, + ): Promise { + this.featureStrategies = this.featureStrategies.map((f) => { + if (f.featureName === featureName) { + f.projectId = newProjectId; + } + return f; + }); + return Promise.resolve(undefined); + } + async setEnvironmentEnabledStatus( environment: string, featureName: string,