mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
This PR updates the feature type service by adding a new `updateLifetime` method. This method handles the connection between the API (#4256) and the store (#4252). I've also added some new e2e tests to ensure that the API behaves as expected.
This commit is contained in:
parent
276261c913
commit
b990c6dfe0
@ -69,12 +69,12 @@ class FeatureTypeStore implements IFeatureTypeStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateLifetime(
|
async updateLifetime(
|
||||||
name: string,
|
id: string,
|
||||||
newLifetimeDays: number | null,
|
newLifetimeDays: number | null,
|
||||||
): Promise<IFeatureType | undefined> {
|
): Promise<IFeatureType | undefined> {
|
||||||
const [updatedType] = await this.db(TABLE)
|
const [updatedType] = await this.db(TABLE)
|
||||||
.update({ lifetime_days: newLifetimeDays })
|
.update({ lifetime_days: newLifetimeDays })
|
||||||
.where({ name })
|
.where({ id })
|
||||||
.returning(['*']);
|
.returning(['*']);
|
||||||
|
|
||||||
if (updatedType) {
|
if (updatedType) {
|
||||||
|
@ -13,13 +13,13 @@ import { createResponseSchema } from '../../openapi/util/create-response-schema'
|
|||||||
import Controller from '../controller';
|
import Controller from '../controller';
|
||||||
import {
|
import {
|
||||||
createRequestSchema,
|
createRequestSchema,
|
||||||
|
featureTypeSchema,
|
||||||
FeatureTypeSchema,
|
FeatureTypeSchema,
|
||||||
getStandardResponses,
|
getStandardResponses,
|
||||||
UpdateFeatureTypeLifetimeSchema,
|
UpdateFeatureTypeLifetimeSchema,
|
||||||
} from '../../openapi';
|
} from '../../openapi';
|
||||||
import { IAuthRequest } from '../unleash-types';
|
import { IAuthRequest } from '../unleash-types';
|
||||||
import { IFlagResolver } from '../../types';
|
import { IFlagResolver } from '../../types';
|
||||||
import NotImplementedError from '../../error/not-implemented-error';
|
|
||||||
|
|
||||||
const version = 1;
|
const version = 1;
|
||||||
|
|
||||||
@ -114,8 +114,16 @@ When a feature toggle type's expected lifetime is changed, this will also cause
|
|||||||
res: Response<FeatureTypeSchema>,
|
res: Response<FeatureTypeSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (this.flagResolver.isEnabled('configurableFeatureTypeLifetimes')) {
|
if (this.flagResolver.isEnabled('configurableFeatureTypeLifetimes')) {
|
||||||
throw new NotImplementedError(
|
const result = await this.featureTypeService.updateLifetime(
|
||||||
"This operation isn't implemented yet",
|
req.params.id.toLowerCase(),
|
||||||
|
req.body.lifetimeDays,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.openApiService.respondWithValidation(
|
||||||
|
200,
|
||||||
|
res,
|
||||||
|
featureTypeSchema.$id,
|
||||||
|
result,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
res.status(409).end();
|
res.status(409).end();
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
IFeatureType,
|
IFeatureType,
|
||||||
IFeatureTypeStore,
|
IFeatureTypeStore,
|
||||||
} from '../types/stores/feature-type-store';
|
} from '../types/stores/feature-type-store';
|
||||||
|
import NotFoundError from '../error/notfound-error';
|
||||||
|
|
||||||
export default class FeatureTypeService {
|
export default class FeatureTypeService {
|
||||||
private featureTypeStore: IFeatureTypeStore;
|
private featureTypeStore: IFeatureTypeStore;
|
||||||
@ -22,6 +23,29 @@ export default class FeatureTypeService {
|
|||||||
async getAll(): Promise<IFeatureType[]> {
|
async getAll(): Promise<IFeatureType[]> {
|
||||||
return this.featureTypeStore.getAll();
|
return this.featureTypeStore.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateLifetime(
|
||||||
|
id: string,
|
||||||
|
newLifetimeDays: number | null,
|
||||||
|
): Promise<IFeatureType> {
|
||||||
|
// because our OpenAPI library does type coercion, any `null` values you
|
||||||
|
// pass in get converted to `0`.
|
||||||
|
const translatedLifetime =
|
||||||
|
newLifetimeDays === 0 ? null : newLifetimeDays;
|
||||||
|
|
||||||
|
const result = await this.featureTypeStore.updateLifetime(
|
||||||
|
id,
|
||||||
|
translatedLifetime,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new NotFoundError(
|
||||||
|
`The feature type you tried to update ("${id}") does not exist.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FeatureTypeService;
|
module.exports = FeatureTypeService;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import dbInit from '../../helpers/database-init';
|
import dbInit from '../../helpers/database-init';
|
||||||
import getLogger from '../../../fixtures/no-logger';
|
import getLogger from '../../../fixtures/no-logger';
|
||||||
import { setupApp } from '../../helpers/test-helper';
|
import { setupAppWithCustomConfig } from '../../helpers/test-helper';
|
||||||
import { validateSchema } from '../../../../lib/openapi/validate';
|
import { validateSchema } from '../../../../lib/openapi/validate';
|
||||||
import { featureTypesSchema } from '../../../../lib/openapi/spec/feature-types-schema';
|
import { featureTypesSchema } from '../../../../lib/openapi/spec/feature-types-schema';
|
||||||
|
|
||||||
@ -9,7 +9,14 @@ let db;
|
|||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('feature_type_api_serial', getLogger);
|
db = await dbInit('feature_type_api_serial', getLogger);
|
||||||
app = await setupApp(db.stores);
|
app = await setupAppWithCustomConfig(db.stores, {
|
||||||
|
experimental: {
|
||||||
|
flags: {
|
||||||
|
configurableFeatureTypeLifetimes: true,
|
||||||
|
strictSchemaValidation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -32,3 +39,44 @@ test('Should get all defined feature types', async () => {
|
|||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('updating lifetimes', () => {
|
||||||
|
test.each([null, 5])(
|
||||||
|
'it updates to the lifetime correctly: `%s`',
|
||||||
|
async (lifetimeDays) => {
|
||||||
|
const { body } = await app.request
|
||||||
|
.put(`/api/admin/feature-types/release/lifetime`)
|
||||||
|
.send({ lifetimeDays })
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.lifetimeDays).toEqual(lifetimeDays);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
test("if the feature type doesn't exist, you get a 404", async () => {
|
||||||
|
await app.request
|
||||||
|
.put(`/api/admin/feature-types/bogus-feature-type/lifetime`)
|
||||||
|
.send({ lifetimeDays: 45 })
|
||||||
|
.expect(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Setting lifetime to `null` is the same as setting it to `0`', async () => {
|
||||||
|
const setLifetime = async (lifetimeDays) => {
|
||||||
|
const { body } = await app.request
|
||||||
|
.put('/api/admin/feature-types/release/lifetime')
|
||||||
|
.send({ lifetimeDays })
|
||||||
|
.expect(200);
|
||||||
|
return body;
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(await setLifetime(0)).toMatchObject(await setLifetime(null));
|
||||||
|
});
|
||||||
|
test('the :id parameter is not case sensitive', async () => {
|
||||||
|
const lifetimeDays = 45;
|
||||||
|
const { body } = await app.request
|
||||||
|
.put(`/api/admin/feature-types/kIlL-SwItCh/lifetime`)
|
||||||
|
.send({ lifetimeDays })
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.lifetimeDays).toEqual(lifetimeDays);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -46,15 +46,13 @@ describe('update lifetimes', () => {
|
|||||||
|
|
||||||
for (const type of featureTypes) {
|
for (const type of featureTypes) {
|
||||||
const updated = await featureTypeStore.updateLifetime(
|
const updated = await featureTypeStore.updateLifetime(
|
||||||
type.name,
|
type.id,
|
||||||
newLifetime,
|
newLifetime,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(updated?.lifetimeDays).toBe(newLifetime);
|
expect(updated?.lifetimeDays).toBe(newLifetime);
|
||||||
|
|
||||||
expect(updated).toMatchObject(
|
expect(updated).toMatchObject(await featureTypeStore.get(type.id));
|
||||||
await featureTypeStore.getByName(type.name),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user