mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-28 00:06:53 +01:00
c17a1980a2
This simplifies stores to just be storage interaction, they no longer react to events. Controllers now call services and awaits the result from the call. When the service calls are returned the database is updated. This simplifies testing dramatically, cause you know that your state is updated when returned from a call, rather than hoping the store has picked up the event (which really was a command) and reacted to it. Events are still emitted from eventStore, so other parts of the app can react to events as they're being sent out. As part of the move to services, we now also emit an application-created event when we see a new client application. Fixes: #685 Fixes: #595
222 lines
5.6 KiB
JavaScript
222 lines
5.6 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('ava');
|
|
|
|
const store = require('../../test/fixtures/store');
|
|
const getLogger = require('../../test/fixtures/no-logger');
|
|
|
|
const StateService = require('./state-service');
|
|
const {
|
|
FEATURE_IMPORT,
|
|
DROP_FEATURES,
|
|
STRATEGY_IMPORT,
|
|
DROP_STRATEGIES,
|
|
} = require('../event-type');
|
|
|
|
function getSetup() {
|
|
const stores = store.createStores();
|
|
return {
|
|
stateService: new StateService(stores, { getLogger }),
|
|
stores,
|
|
};
|
|
}
|
|
|
|
test('should import a feature', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
features: [
|
|
{
|
|
name: 'new-feature',
|
|
enabled: true,
|
|
strategies: [{ name: 'default' }],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stateService.import({ data });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 1);
|
|
t.is(events[0].type, FEATURE_IMPORT);
|
|
t.is(events[0].data.name, 'new-feature');
|
|
});
|
|
|
|
test('should not import an existing feature', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
features: [
|
|
{
|
|
name: 'new-feature',
|
|
enabled: true,
|
|
strategies: [{ name: 'default' }],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stores.featureToggleStore.createFeature(data.features[0]);
|
|
|
|
await stateService.import({ data, keepExisting: true });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 0);
|
|
});
|
|
|
|
test('should not keep existing feature if drop-before-import', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
features: [
|
|
{
|
|
name: 'new-feature',
|
|
enabled: true,
|
|
strategies: [{ name: 'default' }],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stores.featureToggleStore.createFeature(data.features[0]);
|
|
|
|
await stateService.import({
|
|
data,
|
|
keepExisting: true,
|
|
dropBeforeImport: true,
|
|
});
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 2);
|
|
t.is(events[0].type, DROP_FEATURES);
|
|
t.is(events[1].type, FEATURE_IMPORT);
|
|
});
|
|
|
|
test('should drop feature before import if specified', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
features: [
|
|
{
|
|
name: 'new-feature',
|
|
enabled: true,
|
|
strategies: [{ name: 'default' }],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stateService.import({ data, dropBeforeImport: true });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 2);
|
|
t.is(events[0].type, DROP_FEATURES);
|
|
t.is(events[1].type, FEATURE_IMPORT);
|
|
t.is(events[1].data.name, 'new-feature');
|
|
});
|
|
|
|
test('should import a strategy', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
strategies: [
|
|
{
|
|
name: 'new-strategy',
|
|
parameters: [],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stateService.import({ data });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 1);
|
|
t.is(events[0].type, STRATEGY_IMPORT);
|
|
t.is(events[0].data.name, 'new-strategy');
|
|
});
|
|
|
|
test('should not import an exiting strategy', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
strategies: [
|
|
{
|
|
name: 'new-strategy',
|
|
parameters: [],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stores.strategyStore.createStrategy(data.strategies[0]);
|
|
|
|
await stateService.import({ data, keepExisting: true });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 0);
|
|
});
|
|
|
|
test('should drop strategies before import if specified', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {
|
|
strategies: [
|
|
{
|
|
name: 'new-strategy',
|
|
parameters: [],
|
|
},
|
|
],
|
|
};
|
|
|
|
await stateService.import({ data, dropBeforeImport: true });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 2);
|
|
t.is(events[0].type, DROP_STRATEGIES);
|
|
t.is(events[1].type, STRATEGY_IMPORT);
|
|
t.is(events[1].data.name, 'new-strategy');
|
|
});
|
|
|
|
test('should drop neither features nor strategies when neither is imported', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
const data = {};
|
|
|
|
await stateService.import({ data, dropBeforeImport: true });
|
|
|
|
const events = await stores.eventStore.getEvents();
|
|
t.is(events.length, 0);
|
|
});
|
|
|
|
test('should not accept gibberish', async t => {
|
|
const { stateService } = getSetup();
|
|
|
|
const data1 = {
|
|
type: 'gibberish',
|
|
flags: { evil: true },
|
|
};
|
|
const data2 = '{somerandomtext/';
|
|
|
|
await t.throwsAsync(stateService.import({ data: data1 }));
|
|
|
|
await t.throwsAsync(stateService.import({ data: data2 }));
|
|
});
|
|
|
|
test('should export featureToggles', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
stores.featureToggleStore.createFeature({ name: 'a-feature' });
|
|
|
|
const data = await stateService.export({ includeFeatureToggles: true });
|
|
|
|
t.is(data.features.length, 1);
|
|
t.is(data.features[0].name, 'a-feature');
|
|
});
|
|
|
|
test('should export strategies', async t => {
|
|
const { stateService, stores } = getSetup();
|
|
|
|
stores.strategyStore.createStrategy({ name: 'a-strategy', editable: true });
|
|
|
|
const data = await stateService.export({ includeStrategies: true });
|
|
|
|
t.is(data.strategies.length, 1);
|
|
t.is(data.strategies[0].name, 'a-strategy');
|
|
});
|