mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-18 00:19:49 +01:00
feat: Remove applications (#635)
This commit is contained in:
parent
edf6d70116
commit
4a3c136167
@ -87,6 +87,12 @@ class ClientApplicationsDb {
|
|||||||
return mapRow(row);
|
return mapRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteApplication(appName) {
|
||||||
|
return this.db(TABLE)
|
||||||
|
.where('app_name', appName)
|
||||||
|
.del();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Could also be done in SQL:
|
* Could also be done in SQL:
|
||||||
* (not sure if it is faster though)
|
* (not sure if it is faster though)
|
||||||
|
@ -127,6 +127,12 @@ class ClientInstanceStore {
|
|||||||
|
|
||||||
return rows.map(mapRow);
|
return rows.map(mapRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteForApplication(appName) {
|
||||||
|
return this.db(TABLE)
|
||||||
|
.where('app_name', appName)
|
||||||
|
.del();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ClientInstanceStore;
|
module.exports = ClientInstanceStore;
|
||||||
|
@ -32,6 +32,11 @@ class MetricsController extends Controller {
|
|||||||
this.createApplication,
|
this.createApplication,
|
||||||
UPDATE_APPLICATION,
|
UPDATE_APPLICATION,
|
||||||
);
|
);
|
||||||
|
this.delete(
|
||||||
|
'/applications/:appName',
|
||||||
|
this.deleteApplication,
|
||||||
|
UPDATE_APPLICATION,
|
||||||
|
);
|
||||||
this.get('/applications/', this.getApplications);
|
this.get('/applications/', this.getApplications);
|
||||||
this.get('/applications/:appName', this.getApplication);
|
this.get('/applications/:appName', this.getApplication);
|
||||||
}
|
}
|
||||||
@ -76,6 +81,27 @@ class MetricsController extends Controller {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteApplication(req, res) {
|
||||||
|
const { appName } = req.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.clientApplicationsStore.getApplication(appName);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(e);
|
||||||
|
res.status(409).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.clientInstanceStore.deleteForApplication(appName);
|
||||||
|
await this.clientApplicationsStore.deleteApplication(appName);
|
||||||
|
res.status(200).end();
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(e);
|
||||||
|
res.status(500).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async createApplication(req, res) {
|
async createApplication(req, res) {
|
||||||
const input = { ...req.body, appName: req.params.appName };
|
const input = { ...req.body, appName: req.params.appName };
|
||||||
const { value: applicationData, error } = schema.validate(input);
|
const { value: applicationData, error } = schema.validate(input);
|
||||||
|
@ -154,3 +154,27 @@ test('should store application details wihtout strategies', t => {
|
|||||||
.send({ appName, url: 'htto://asd.com' })
|
.send({ appName, url: 'htto://asd.com' })
|
||||||
.expect(202);
|
.expect(202);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should not delete unknown application', t => {
|
||||||
|
t.plan(0);
|
||||||
|
const { request, perms } = getSetup();
|
||||||
|
const appName = 'unknown';
|
||||||
|
perms.withPermissions(UPDATE_APPLICATION);
|
||||||
|
|
||||||
|
return request
|
||||||
|
.delete(`/api/admin/metrics/applications/${appName}`)
|
||||||
|
.expect(409);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should delete application', t => {
|
||||||
|
t.plan(0);
|
||||||
|
const { request, stores, perms } = getSetup();
|
||||||
|
const appName = 'deletable-test';
|
||||||
|
|
||||||
|
perms.withPermissions(UPDATE_APPLICATION);
|
||||||
|
stores.clientApplicationsStore.upsert({ appName });
|
||||||
|
|
||||||
|
return request
|
||||||
|
.delete(`/api/admin/metrics/applications/${appName}`)
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
@ -22,61 +22,6 @@ test.afterEach(async () => {
|
|||||||
await reset();
|
await reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.serial('should register client', async t => {
|
|
||||||
t.plan(0);
|
|
||||||
const request = await setupApp(stores);
|
|
||||||
return request
|
|
||||||
.post('/api/client/register')
|
|
||||||
.send({
|
|
||||||
appName: 'demo',
|
|
||||||
instanceId: 'test',
|
|
||||||
strategies: ['default'],
|
|
||||||
started: Date.now(),
|
|
||||||
interval: 10,
|
|
||||||
})
|
|
||||||
.expect(202);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.serial('should allow client to register multiple times', async t => {
|
|
||||||
t.plan(0);
|
|
||||||
const request = await setupApp(stores);
|
|
||||||
const clientRegistration = {
|
|
||||||
appName: 'multipleRegistration',
|
|
||||||
instanceId: 'test',
|
|
||||||
strategies: ['default', 'another'],
|
|
||||||
started: Date.now(),
|
|
||||||
interval: 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
return request
|
|
||||||
.post('/api/client/register')
|
|
||||||
.send(clientRegistration)
|
|
||||||
.expect(202)
|
|
||||||
.then(() =>
|
|
||||||
request
|
|
||||||
.post('/api/client/register')
|
|
||||||
.send(clientRegistration)
|
|
||||||
.expect(202),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.serial('should accept client metrics', async t => {
|
|
||||||
t.plan(0);
|
|
||||||
const request = await setupApp(stores);
|
|
||||||
return request
|
|
||||||
.post('/api/client/metrics')
|
|
||||||
.send({
|
|
||||||
appName: 'demo',
|
|
||||||
instanceId: '1',
|
|
||||||
bucket: {
|
|
||||||
start: Date.now(),
|
|
||||||
stop: Date.now(),
|
|
||||||
toggles: {},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.expect(202);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.serial('should get application details', async t => {
|
test.serial('should get application details', async t => {
|
||||||
t.plan(3);
|
t.plan(3);
|
||||||
const request = await setupApp(stores);
|
const request = await setupApp(stores);
|
||||||
@ -98,6 +43,32 @@ test.serial('should get list of applications', async t => {
|
|||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(res => {
|
.expect(res => {
|
||||||
t.true(res.status === 200);
|
t.true(res.status === 200);
|
||||||
|
t.is(res.body.applications.length, 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('should delete application', async t => {
|
||||||
|
t.plan(2);
|
||||||
|
const request = await setupApp(stores);
|
||||||
|
await request
|
||||||
|
.delete('/api/admin/metrics/applications/deletable-app')
|
||||||
|
.expect(res => {
|
||||||
|
t.is(res.status, 200);
|
||||||
|
});
|
||||||
|
return request
|
||||||
|
.get('/api/admin/metrics/applications')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(res => {
|
||||||
t.is(res.body.applications.length, 2);
|
t.is(res.body.applications.length, 2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.serial('should get 409 when deleting unknwn application', async t => {
|
||||||
|
t.plan(1);
|
||||||
|
const request = await setupApp(stores);
|
||||||
|
return request
|
||||||
|
.delete('/api/admin/metrics/applications/unkown')
|
||||||
|
.expect(res => {
|
||||||
|
t.is(res.status, 409);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -37,3 +37,58 @@ test.serial('should require valid send metrics', async t => {
|
|||||||
})
|
})
|
||||||
.expect(400);
|
.expect(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.serial('should register client', async t => {
|
||||||
|
t.plan(0);
|
||||||
|
const request = await setupApp(stores);
|
||||||
|
return request
|
||||||
|
.post('/api/client/register')
|
||||||
|
.send({
|
||||||
|
appName: 'demo',
|
||||||
|
instanceId: 'test',
|
||||||
|
strategies: ['default'],
|
||||||
|
started: Date.now(),
|
||||||
|
interval: 10,
|
||||||
|
})
|
||||||
|
.expect(202);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('should allow client to register multiple times', async t => {
|
||||||
|
t.plan(0);
|
||||||
|
const request = await setupApp(stores);
|
||||||
|
const clientRegistration = {
|
||||||
|
appName: 'multipleRegistration',
|
||||||
|
instanceId: 'test',
|
||||||
|
strategies: ['default', 'another'],
|
||||||
|
started: Date.now(),
|
||||||
|
interval: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
return request
|
||||||
|
.post('/api/client/register')
|
||||||
|
.send(clientRegistration)
|
||||||
|
.expect(202)
|
||||||
|
.then(() =>
|
||||||
|
request
|
||||||
|
.post('/api/client/register')
|
||||||
|
.send(clientRegistration)
|
||||||
|
.expect(202),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial('should accept client metrics', async t => {
|
||||||
|
t.plan(0);
|
||||||
|
const request = await setupApp(stores);
|
||||||
|
return request
|
||||||
|
.post('/api/client/metrics')
|
||||||
|
.send({
|
||||||
|
appName: 'demo',
|
||||||
|
instanceId: '1',
|
||||||
|
bucket: {
|
||||||
|
start: Date.now(),
|
||||||
|
stop: Date.now(),
|
||||||
|
toggles: {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect(202);
|
||||||
|
});
|
||||||
|
@ -30,6 +30,11 @@
|
|||||||
"appName": "demo-app-2",
|
"appName": "demo-app-2",
|
||||||
"strategies": ["default", "extra"],
|
"strategies": ["default", "extra"],
|
||||||
"description": "hello"
|
"description": "hello"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appName": "deletable-app",
|
||||||
|
"strategies": ["default"],
|
||||||
|
"description": "Some desc"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"clientInstances": [
|
"clientInstances": [
|
||||||
@ -46,6 +51,13 @@
|
|||||||
"strategies": ["default"],
|
"strategies": ["default"],
|
||||||
"started": 1516026938494,
|
"started": 1516026938494,
|
||||||
"interval": 10
|
"interval": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appName": "deletable-app",
|
||||||
|
"instanceId": "inst-1",
|
||||||
|
"strategies": ["default"],
|
||||||
|
"started": 1516026938494,
|
||||||
|
"interval": 10
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"features": [
|
"features": [
|
||||||
|
13
test/fixtures/fake-client-applications-store.js
vendored
13
test/fixtures/fake-client-applications-store.js
vendored
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
const apps = [];
|
let apps = [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
upsert: app => {
|
upsert: app => {
|
||||||
@ -9,6 +9,15 @@ module.exports = () => {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
getApplications: () => Promise.resolve(apps),
|
getApplications: () => Promise.resolve(apps),
|
||||||
getApplication: appName => apps.filter(a => a.name === appName)[0],
|
getApplication: appName => {
|
||||||
|
const app = apps.filter(a => a.appName === appName)[0];
|
||||||
|
if (!app) {
|
||||||
|
throw new Error(`Could not find app=${appName}`);
|
||||||
|
}
|
||||||
|
return app;
|
||||||
|
},
|
||||||
|
deleteApplication: appName => {
|
||||||
|
apps = apps.filter(app => app.appName !== appName);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
1
test/fixtures/fake-client-instance-store.js
vendored
1
test/fixtures/fake-client-instance-store.js
vendored
@ -3,4 +3,5 @@
|
|||||||
module.exports = () => ({
|
module.exports = () => ({
|
||||||
insert: () => Promise.resolve(),
|
insert: () => Promise.resolve(),
|
||||||
getApplications: () => Promise.resolve([]),
|
getApplications: () => Promise.resolve([]),
|
||||||
|
deleteForApplication: () => Promise.resolve(),
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user