banana
/
definma-api
Archived
2
Fork 0
This repository has been archived on 2023-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
definma-api/src/routes/model.spec.ts

549 lines
16 KiB
TypeScript

import should from 'should/as-function';
import ModelFileModel from '../models/model_file';
import TestHelper from "../test/helper";
import ModelModel from '../models/model';
import UserModel from '../models/user';
import mongoose from 'mongoose';
describe('/model', () => {
let server;
before(done => TestHelper.before(done));
beforeEach(done => server = TestHelper.beforeEach(server, done));
afterEach(done => TestHelper.afterEach(server, done));
after(done => TestHelper.after(done));
describe('GET /model/groups', () => {
it('returns all groups for an admin user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/groups',
auth: {basic: 'admin'},
httpStatus: 200,
}).end((err, res) => {
if (err) return done (err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.models.length);
should(res.body).matchEach(group => {
should(group).have.only.keys('group', 'models');
should(group).have.property('group').be.type('string');
should(group.models).matchEach(model => {
should(model).have.only.keys('_id', 'name', 'url');
should(model).have.property('_id').be.type('string');
should(model).have.property('name').be.type('string');
should(model).have.property('url').be.type('string');
});
});
done();
});
});
it('returns all allowed groups for a predict user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/groups',
auth: {basic: 'customer'},
httpStatus: 200,
}).end((err, res) => {
if (err) return done (err);
should(res.body).have.lengthOf(1);
should(res.body).matchEach(group => {
should(group).have.only.keys('group', 'models');
should(group).have.property('group').be.type('string');
should(group).have.property('models', [{_id: '120000000000000000000001', name: 'Model A', url: 'http://model-a.com'}]);
});
done();
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/groups',
auth: {key: 'janedoe'},
httpStatus: 401,
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/groups',
httpStatus: 401,
});
});
});
describe('POST /model/{group}', () => {
it('adds a new model', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 200,
req: {name: 'Model C', url: 'http://model-c.com'}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelModel.findOne({group: 'VN'}).lean().exec((err, res) => {
if (err) return done(err);
const model = res.models.find(e => e.name === 'Model C');
should(model).have.property('url', 'http://model-c.com');
done();
});
});
});
it('adds a new group', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/classification',
auth: {basic: 'admin'},
httpStatus: 200,
req: {name: 'Model 0.1', url: 'http://model-0-1.com'}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelModel.findOne({group: 'classification'}).lean().exec((err, res) => {
if (err) return done(err);
should(res).have.only.keys('_id', 'group', 'models', '__v');
should(res).have.property('group', 'classification');
should(res.models[0]).have.only.keys('_id', 'name', 'url');
should(res.models[0]).have.property('name', 'Model 0.1');
should(res.models[0]).have.property('url', 'http://model-0-1.com');
done();
});
});
});
it('replaces a model', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 200,
req: {name: 'Model A', url: 'http://model-a-new.com'}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelModel.findOne({group: 'VN'}).lean().exec((err, res) => {
if (err) return done(err);
const model = res.models.find(e => e.name === 'Model A');
should(model).have.property('url', 'http://model-a-new.com');
done();
});
});
});
it('rejects an empty name', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 400,
req: {name: '', url: 'http://model-c.com'},
res:{status: 'Invalid body format', details: '"name" is not allowed to be empty'}
});
});
it('rejects a missing name', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 400,
req: {url: 'http://model-c.com'},
res:{status: 'Invalid body format', details: '"name" is required'}
});
});
it('rejects an invalid URL', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 400,
req: {name: 'Model C', url: 'model-c'},
res:{status: 'Invalid body format', details: '"url" must be a valid uri'}
});
});
it('rejects a missing URL', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'admin'},
httpStatus: 400,
req: {name: 'Model C'},
res:{status: 'Invalid body format', details: '"url" is required'}
});
});
it('rejects a write user', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {basic: 'janedoe'},
httpStatus: 403,
req: {name: 'Model C', url: 'http://model-c.com'}
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
auth: {key: 'admin'},
httpStatus: 401,
req: {name: 'Model C', url: 'http://model-c.com'}
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/VN',
httpStatus: 401,
req: {name: 'Model C', url: 'http://model-c.com'}
});
});
});
describe('DELETE /model/{group}/{name}', () => {
it('deletes the model', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/Model%20A',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelModel.findOne({group: 'VN'}).lean().exec((err, res) => {
if (err) return done(err);
should(res).have.only.keys('_id', 'group', 'models');
should(res).have.property('group', 'VN');
should(res.models[0]).have.only.keys('_id', 'name', 'url');
should(res.models[0]).have.property('name', 'Model B');
should(res.models[0]).have.property('url', 'http://model-b.com');
done();
});
});
});
it('deletes the group, if empty afterwards', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/Moisture/Model%201',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelModel.find({group: 'Moisture'}).lean().exec((err, res) => {
if (err) return done(err);
should(res).have.lengthOf(0);
done();
});
});
});
it ('removes the model_id from all user.models', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/Model%20A',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
UserModel.find({models: mongoose.Types.ObjectId("120000000000000000000001")}).lean().exec((err, res) => {
if (err) return done(err);
should(res).have.lengthOf(0);
done();
});
});
});
it('returns 404 for an unknown group', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/xxx/Model%201',
auth: {basic: 'admin'},
httpStatus: 404
});
});
it('returns 404 for an unknown model', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/xxx',
auth: {basic: 'admin'},
httpStatus: 404
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/Model%20A',
auth: {key: 'admin'},
httpStatus: 401
});
});
it('rejects a write user', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/Model%20A',
auth: {basic: 'janedoe'},
httpStatus: 403
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/VN/Model%20A',
httpStatus: 401
});
});
});
describe('GET /model/files', () => {
it('rejects a write user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/files',
auth: {basic: 'janedoe'},
httpStatus: 403,
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/files',
auth: {key: 'admin'},
httpStatus: 401,
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/files',
httpStatus: 401,
});
});
});
describe('GET /model/file/{name}', (() => {
it('returns the binary data', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/file/modela',
auth: {basic: 'admin'},
httpStatus: 200,
contentType: 'application/octet-stream; charset=utf-8',
}).end((err, res) => {
if (err) return done (err);
should(res.body.toString()).be.eql('binary data');
done();
});
});
it('returns the binary data for an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/file/modela',
auth: {key: 'admin'},
httpStatus: 200,
contentType: 'application/octet-stream; charset=utf-8',
}).end((err, res) => {
if (err) return done (err);
should(res.body.toString()).be.eql('binary data');
done();
});
});
it('returns 404 for an unknown name', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/file/modelx',
auth: {basic: 'admin'},
httpStatus: 404
})
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/file/modela',
auth: {basic: 'janedoe'},
httpStatus: 403
})
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/file/modela',
httpStatus: 401
})
});
}));
describe('POST /model/file/{name}', () => {
it('stores the data', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/file/modelb',
auth: {basic: 'admin'},
httpStatus: 200,
reqContentType: 'application/octet-stream',
req: 'another binary data'
}).end((err, res) => {
if (err) return done (err);
should(res.body).be.eql({status: 'OK'});
ModelFileModel.find({name: 'modelb'}).lean().exec((err, data) => {
if (err) return done (err);
should(data).have.lengthOf(1);
should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
should(data[0]).have.property('name', 'modelb');
should(data[0].data.buffer.toString()).be.eql('another binary data');
done();
});
});
});
it('stores the data with an API key', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/file/modelb',
auth: {key: 'admin'},
httpStatus: 200,
reqContentType: 'application/octet-stream',
req: 'another binary data'
}).end((err, res) => {
if (err) return done (err);
should(res.body).be.eql({status: 'OK'});
ModelFileModel.find({name: 'modelb'}).lean().exec((err, data) => {
if (err) return done (err);
should(data).have.lengthOf(1);
should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
should(data[0]).have.property('name', 'modelb');
should(data[0].data.buffer.toString()).be.eql('another binary data');
done();
});
});
});
it('overwrites existing data', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/file/modela',
auth: {basic: 'admin'},
httpStatus: 200,
reqContentType: 'application/octet-stream',
req: 'another binary data'
}).end((err, res) => {
if (err) return done (err);
should(res.body).be.eql({status: 'OK'});
ModelFileModel.find({name: 'modela'}).lean().exec((err, data) => {
if (err) return done (err);
should(data).have.lengthOf(1);
should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
should(data[0]).have.property('name', 'modela');
should(data[0].data.buffer.toString()).be.eql('another binary data');
done();
});
});
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/file/modelb',
auth: {basic: 'janedoe'},
httpStatus: 403,
req: 'another binary data'
});
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/model/file/modelb',
httpStatus: 401,
req: 'another binary data'
});
});
});
describe('DELETE /model/file/{name}', () => {
it('deletes the data', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/file/modela',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
ModelFileModel.find({name: 'modela'}).lean().exec((err, data) => {
if (err) return done(err);
should(data).have.lengthOf(0);
done();
});
});
});
it('returns 404 for an unknown name', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/file/modelx',
auth: {basic: 'admin'},
httpStatus: 404
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/file/modela',
auth: {key: 'admin'},
httpStatus: 401
});
});
it('rejects a write user', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/file/modela',
auth: {basic: 'janedoe'},
httpStatus: 403
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/model/file/modela',
httpStatus: 401
});
});
});
describe('GET /model/authorized/{url}', () => {
it('returns OK for every model for admins', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/authorized/xx',
auth: {basic: 'admin'},
httpStatus: 200,
res: {status: 'OK'}
});
});
it('returns OK for a specified model for a predict user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/authorized/http%3A%2F%2Fmodel-a.com',
auth: {basic: 'customer'},
httpStatus: 200,
res: {status: 'OK'}
});
});
it('rejects a model not specified for a predict user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/authorized/http%3A%2F%2Fmodel-b.com',
auth: {basic: 'customer'},
httpStatus: 403
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/authorized/xx',
auth: {key: 'admin'},
httpStatus: 401
});
});
it('rejects an unauthorized request', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/model/authorized/http%3A%2F%2Fmodel-b.com',
httpStatus: 401
});
});
});
});