1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: Added tags to events table and emitted events

fixes: #695
This commit is contained in:
Christopher Kolstad 2021-01-27 11:27:35 +01:00
parent 01074fd437
commit bd94f358c3
No known key found for this signature in database
GPG Key ID: 319DE53FE911815A
6 changed files with 127 additions and 8 deletions

View File

@ -3,7 +3,14 @@
const { EventEmitter } = require('events');
const { DROP_FEATURES } = require('../event-type');
const EVENT_COLUMNS = ['id', 'type', 'created_by', 'created_at', 'data'];
const EVENT_COLUMNS = [
'id',
'type',
'created_by',
'created_at',
'data',
'tags',
];
class EventStore extends EventEmitter {
constructor(db) {
@ -14,8 +21,9 @@ class EventStore extends EventEmitter {
async store(event) {
await this.db('events').insert({
type: event.type,
created_by: event.createdBy, // eslint-disable-line
created_by: event.createdBy, // eslint-disable-line
data: event.data,
tags: event.tags ? JSON.stringify(event.tags) : [],
});
this.emit(event.type, event);
}
@ -56,6 +64,7 @@ class EventStore extends EventEmitter {
createdBy: row.created_by,
createdAt: row.created_at,
data: row.data,
tags: row.tags,
};
}
}

View File

@ -83,7 +83,7 @@ test('should revive toggle', t => {
});
test('should create event when reviving toggle', async t => {
t.plan(4);
t.plan(6);
const name = 'name1';
const {
request,
@ -99,13 +99,24 @@ test('should create event when reviving toggle', async t => {
strategies: [{ name: 'default' }],
});
await featureToggleService.addTag(
name,
{
type: 'simple',
value: 'tag',
},
'test@test.com',
);
await request.post(`${base}/api/admin/archive/revive/${name}`);
const events = await eventStore.getEvents();
t.is(events.length, 1);
t.is(events[0].type, 'feature-revived');
t.is(events[0].data.name, name);
t.is(events[0].createdBy, 'unknown');
t.is(events.length, 3);
t.is(events[2].type, 'feature-revived');
t.is(events[2].data.name, name);
t.is(events[2].createdBy, 'unknown');
t.is(events[2].tags[0].type, 'simple');
t.is(events[2].tags[0].value, 'tag');
});
test('should require toggle name when reviving', t => {

View File

@ -8,7 +8,11 @@ const { createServices } = require('../../services');
const permissions = require('../../../test/fixtures/permissions');
const getLogger = require('../../../test/fixtures/no-logger');
const getApp = require('../../app');
const { UPDATE_FEATURE, CREATE_FEATURE } = require('../../permissions');
const {
UPDATE_FEATURE,
CREATE_FEATURE,
DELETE_FEATURE,
} = require('../../permissions');
const eventBus = new EventEmitter();
@ -31,6 +35,7 @@ function getSetup() {
base,
perms,
featureToggleStore: stores.featureToggleStore,
eventStore: stores.eventStore,
request: supertest(app),
};
}
@ -523,3 +528,55 @@ test('Should be able to filter on project', t => {
t.is(res.body.features[1].name, 'a_tag.toggle');
});
});
test('Tags should be included in archive events', async t => {
const { request, eventStore, featureToggleStore, base, perms } = getSetup();
perms.withPermissions(UPDATE_FEATURE, DELETE_FEATURE);
featureToggleStore.createFeature({
name: 'a_team.toggle',
enabled: false,
strategies: [{ name: 'default' }],
project: 'projecta',
});
featureToggleStore.tagFeature('a_team.toggle', {
type: 'simple',
value: 'tag',
});
await request
.delete(`${base}/api/admin/features/a_team.toggle`)
.expect(200);
const events = await eventStore.getEvents();
t.is(events[0].type, 'feature-archived');
t.is(events[0].tags[0].type, 'simple');
t.is(events[0].tags[0].value, 'tag');
});
test('Tags should be included in updated events', async t => {
const { request, eventStore, featureToggleStore, base, perms } = getSetup();
perms.withPermissions(UPDATE_FEATURE, DELETE_FEATURE);
featureToggleStore.createFeature({
name: 'a_team.toggle',
enabled: false,
strategies: [{ name: 'default' }],
project: 'projecta',
});
featureToggleStore.tagFeature('a_team.toggle', {
type: 'simple',
value: 'tag',
});
await request
.put(`${base}/api/admin/features/a_team.toggle`)
.send({
name: 'a_team.toggle',
enabled: false,
strategies: [{ name: 'default' }],
project: 'projectb',
})
.expect(200);
const events = await eventStore.getEvents();
t.is(events[0].type, 'feature-updated');
t.is(events[0].tags[0].type, 'simple');
t.is(events[0].tags[0].value, 'tag');
});

View File

@ -75,29 +75,41 @@ class FeatureToggleService {
await this.featureToggleStore.getFeature(updatedFeature.name);
const value = await featureSchema.validateAsync(updatedFeature);
await this.featureToggleStore.updateFeature(value);
const tags =
(await this.featureToggleStore.getAllTagsForFeature(
updatedFeature.name,
)) || [];
await this.eventStore.store({
type: FEATURE_UPDATED,
createdBy: userName,
data: updatedFeature,
tags,
});
}
async archiveToggle(name, userName) {
await this.featureToggleStore.getFeature(name);
await this.featureToggleStore.archiveFeature(name);
const tags =
(await this.featureToggleStore.getAllTagsForFeature(name)) || [];
await this.eventStore.store({
type: FEATURE_ARCHIVED,
createdBy: userName,
data: { name },
tags,
});
}
async reviveToggle(name, userName) {
await this.featureToggleStore.reviveFeature({ name });
const tags =
(await this.featureToggleStore.getAllTagsForFeature(name)) || [];
await this.eventStore.store({
type: FEATURE_REVIVED,
createdBy: userName,
data: { name },
tags,
});
}
@ -181,10 +193,15 @@ class FeatureToggleService {
const feature = await this.featureToggleStore.getFeature(featureName);
feature[field] = value;
await this.featureToggleStore.updateFeature(feature);
const tags =
(await this.featureToggleStore.getAllTagsForFeature(featureName)) ||
[];
await this.eventStore.store({
type: FEATURE_UPDATED,
createdBy: userName,
data: feature,
tags,
});
return feature;
}

View File

@ -0,0 +1,18 @@
'use strict';
exports.up = function(db, cb) {
db.runSql(
`
ALTER TABLE events ADD COLUMN IF NOT EXISTS tags json DEFAULT '[]'
`,
cb,
);
};
exports.down = function(db, cb) {
db.runSql(
`
ALTER TABLE events DROP COLUMN IF EXISTS tags;
`,
cb,
);
};

View File

@ -31,6 +31,13 @@ module.exports = () => {
);
_features.push(updatedFeature);
},
archiveFeature: feature => {
_features.slice(
_features.indexOf(({ name }) => name === feature.name),
1,
);
_archive.push(feature);
},
createFeature: feature => _features.push(feature),
getArchivedFeatures: () => Promise.resolve(_archive),
addArchivedFeature: feature => _archive.push(feature),