1
0
Fork 0

Fix Foxx API (#4614)

This commit is contained in:
Mark 2018-02-20 10:22:27 +01:00 committed by Jan
parent 1c80774091
commit cd97787adf
5 changed files with 75 additions and 9 deletions

View File

@ -1,6 +1,11 @@
devel devel
----- -----
* fixed Foxx API:
* PUT /_api/foxx/service: Respect force flag
* PATCH /_api/foxx/service: Check whether a service under given mount exists
* renamed startup option `--replication.automatic-failover` to * renamed startup option `--replication.automatic-failover` to
`--replication.active-failover` `--replication.active-failover`
using the old option name will still work in ArangoDB 3.4, but the old option using the old option name will still work in ArangoDB 3.4, but the old option

View File

@ -53,6 +53,9 @@ Set to `false` to not run the new service's setup script.
@RESTQUERYPARAM{legacy,boolean,optional} @RESTQUERYPARAM{legacy,boolean,optional}
Set to `true` to install the new service in 2.8 legacy compatibility mode. Set to `true` to install the new service in 2.8 legacy compatibility mode.
@RESTQUERYPARAM{force,boolean,optional}
Set to `true` to force service install even if no service is installed under given mount.
@RESTRETURNCODES @RESTRETURNCODES
@RESTRETURNCODE{200} @RESTRETURNCODE{200}

View File

@ -199,6 +199,7 @@ serviceRouter.put(prepareServiceRequestBody, (req, res) => {
.queryParam('teardown', schemas.flag.default(true)) .queryParam('teardown', schemas.flag.default(true))
.queryParam('setup', schemas.flag.default(true)) .queryParam('setup', schemas.flag.default(true))
.queryParam('legacy', schemas.flag.default(false)) .queryParam('legacy', schemas.flag.default(false))
.queryParam('force', schemas.flag.default(false))
.response(200, schemas.fullInfo); .response(200, schemas.fullInfo);
serviceRouter.delete((req, res) => { serviceRouter.delete((req, res) => {

View File

@ -1288,8 +1288,8 @@ describe('Foxx service', () => {
const routes = [ const routes = [
['GET', '/_api/foxx/service'], ['GET', '/_api/foxx/service'],
['PATCH', '/_api/foxx/service'], ['PATCH', '/_api/foxx/service', { source: servicePath }],
['PUT', '/_api/foxx/service'], ['PUT', '/_api/foxx/service', { source: servicePath }],
['DELETE', '/_api/foxx/service'], ['DELETE', '/_api/foxx/service'],
['GET', '/_api/foxx/configuration'], ['GET', '/_api/foxx/configuration'],
['PATCH', '/_api/foxx/configuration'], ['PATCH', '/_api/foxx/configuration'],
@ -1306,20 +1306,22 @@ describe('Foxx service', () => {
['GET', '/_api/foxx/readme'], ['GET', '/_api/foxx/readme'],
['GET', '/_api/foxx/swagger'] ['GET', '/_api/foxx/swagger']
]; ];
for (const [method, url] of routes) { for (const [method, url, body] of routes) {
it(`should return 400 when mount is omitted for ${method} ${url}`, () => { it(`should return 400 when mount is omitted for ${method} ${url}`, () => {
const resp = request({ const resp = request({
method, method,
url, url,
body,
json: true json: true
}); });
expect(resp.status).to.equal(400); expect(resp.status).to.equal(400);
}); });
it(`should return 400 when mount is invalid for ${method} ${url}`, () => { it(`should return 400 when mount is unknown for ${method} ${url}`, () => {
const resp = request({ const resp = request({
method, method,
url, url,
qs: {mount: '/dev/null'}, qs: {mount: '/dev/null'},
body,
json: true json: true
}); });
expect(resp.status).to.equal(400); expect(resp.status).to.equal(400);
@ -1337,4 +1339,36 @@ describe('Foxx service', () => {
expect(resp.json).to.have.property('failures'); expect(resp.json).to.have.property('failures');
expect(resp.json).to.have.property('passes'); expect(resp.json).to.have.property('passes');
}); });
it('replace on invalid mount should not be installed', () => {
const replaceResp = request.put('/_api/foxx/service', {
qs: {
mount
},
body: {
source: servicePath
},
json: true
});
expect(replaceResp.status).to.equal(400);
const resp = request.get(mount);
expect(resp.status).to.equal(404);
});
it('replace on invalid mount should be installed when forced', () => {
const replaceResp = request.put('/_api/foxx/service', {
qs: {
mount,
force: true
},
body: {
source: servicePath
},
json: true
});
expect(replaceResp.status).to.equal(200);
const resp = request.get(mount);
expect(resp.status).to.equal(200);
expect(resp.json).to.eql({hello: 'world'});
});
}); });

View File

@ -860,8 +860,21 @@ function uninstall (mount, options = {}) {
} }
function replace (serviceInfo, mount, options = {}) { function replace (serviceInfo, mount, options = {}) {
utils.validateMount(mount);
ensureFoxxInitialized(); ensureFoxxInitialized();
if (!options.force) {
const serviceDefinition = utils.getServiceDefinition(mount);
if (!serviceDefinition) {
throw new ArangoError({
errorNum: errors.ERROR_SERVICE_NOT_FOUND.code,
errorMessage: dd`
${errors.ERROR_SERVICE_NOT_FOUND.message}
Mount path: "${mount}".
`
});
}
} else {
utils.validateMount(mount);
}
const tempPaths = _prepareService(serviceInfo, options); const tempPaths = _prepareService(serviceInfo, options);
FoxxService.validatedManifest({ FoxxService.validatedManifest({
mount, mount,
@ -877,7 +890,17 @@ function replace (serviceInfo, mount, options = {}) {
function upgrade (serviceInfo, mount, options = {}) { function upgrade (serviceInfo, mount, options = {}) {
ensureFoxxInitialized(); ensureFoxxInitialized();
const serviceOptions = utils.getServiceDefinition(mount).options; const serviceDefinition = utils.getServiceDefinition(mount);
if (!serviceDefinition) {
throw new ArangoError({
errorNum: errors.ERROR_SERVICE_NOT_FOUND.code,
errorMessage: dd`
${errors.ERROR_SERVICE_NOT_FOUND.message}
Mount path: "${mount}".
`
});
}
const serviceOptions = serviceDefinition.options;
Object.assign(serviceOptions.configuration, options.configuration); Object.assign(serviceOptions.configuration, options.configuration);
Object.assign(serviceOptions.dependencies, options.dependencies); Object.assign(serviceOptions.dependencies, options.dependencies);
serviceOptions.development = options.development; serviceOptions.development = options.development;