Skip to content

Commit

Permalink
fix: return 400 when enabling env of archived toggle (#6049)
Browse files Browse the repository at this point in the history
Creates a new ArchivedFeatureError.
Throw this error when trying to toggle a feature environment for an
archived feature.

Closes
https://github.com/orgs/Unleash/projects/8/views/1?pane=issue&itemId=51242922

Signed-off-by: andreas-unleash <[email protected]>
  • Loading branch information
andreas-unleash authored Jan 26, 2024
1 parent a1fa5a4 commit 4a2d1b0
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/lib/error/archivedfeature-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { UnleashError } from './unleash-error';

class ArchivedFeatureError extends UnleashError {
statusCode = 400;

constructor(
message: string = 'Cannot perform this operation on archived features',
) {
super(message);
}
}
export default ArchivedFeatureError;
module.exports = ArchivedFeatureError;
14 changes: 14 additions & 0 deletions src/lib/features/feature-toggle/feature-toggle-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ import { IDependentFeaturesReadModel } from '../dependent-features/dependent-fea
import EventService from '../events/event-service';
import { DependentFeaturesService } from '../dependent-features/dependent-features-service';
import { FeatureToggleInsert } from './feature-toggle-store';
import ArchivedFeatureError from '../../error/archivedfeature-error';

interface IFeatureContext {
featureName: string;
Expand Down Expand Up @@ -259,6 +260,17 @@ class FeatureToggleService {
}
}

async validateFeatureIsNotArchived(
featureName: string,
project: string,
): Promise<void> {
const toggle = await this.featureToggleStore.get(featureName);

if (toggle.archived || Boolean(toggle.archivedAt)) {
throw new ArchivedFeatureError();
}
}

async validateNoChildren(featureName: string): Promise<void> {
const children = await this.dependentFeaturesReadModel.getChildren([
featureName,
Expand Down Expand Up @@ -1748,6 +1760,8 @@ class FeatureToggleService {
);
}

await this.validateFeatureIsNotArchived(featureName, project);

if (enabled) {
const strategies = await this.getStrategiesForEnvironment(
project,
Expand Down
44 changes: 44 additions & 0 deletions src/lib/features/feature-toggle/tests/feature-toggles.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,50 @@ test('Disabling environment creates a FEATURE_ENVIRONMENT_DISABLED event', async
expect(ourFeatureEvent).toBeTruthy();
});

test('Returns 400 when toggling environment of archived feature', async () => {
const environment = 'environment_test_archived';
const featureName = 'test_archived_feature';

// Create environment
await db.stores.environmentStore.create({
name: environment,
type: 'test',
});
// Connect environment to project
await app.request
.post('/api/admin/projects/default/environments')
.send({ environment })
.expect(200);

// Create feature
await app.request
.post('/api/admin/projects/default/features')
.send({
name: featureName,
})
.set('Content-Type', 'application/json')
.expect(201);
// Archive feature
await app.request
.delete(`/api/admin/projects/default/features/${featureName}`)
.set('Content-Type', 'application/json')
.expect(202);

await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${environment}/strategies`,
)
.send({ name: 'default', constraints: [] })
.expect(200);

await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${environment}/on`,
)
.set('Content-Type', 'application/json')
.expect(400);
});

test('Can delete strategy from feature toggle', async () => {
const envName = 'del-strategy';
const featureName = 'feature.strategy.toggle.delete.strategy';
Expand Down

0 comments on commit 4a2d1b0

Please sign in to comment.