periodicjs
Version:
Periodic is a rapid enterprise application framework for data driven web and mobile applications.
524 lines (522 loc) • 17.2 kB
JavaScript
'use strict';
/*jshint expr: true*/
const path = require('path');
const events = require('events');
const chai = require('chai');
const sinon = require('sinon');
const fs = require('fs-extra');
const expect = require('chai').expect;
const periodic = require('../../../index');
const periodicClass = require('../../../lib/periodicClass');
const config = require('../../../lib/init/config');
const configSequelizeSchema = require('../../../lib/schemas/config.sequelize');
const testPathDir = path.resolve(__dirname, '../../mock/spec/periodic');
const initTestPathDir = path.join(testPathDir, 'configTest');
const CoreData = require('periodicjs.core.data');
const initTestConfigJsonFile = path.join(initTestPathDir, 'content/config/config.json');
const configTestConfigJson = require('../../mock/config/config_test_config');
const extDoc = require('../../mock/config/ext_doc');
let configPeriodic;
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
require('mocha-sinon');
describe('Periodic Init Config', function() {
this.timeout(10000);
before('initialize config test periodic dir', (done) => {
fs.ensureDir(initTestPathDir)
.then(() => {
return fs.ensureDir(path.join(initTestPathDir, 'content/config'));
})
.then(() => {
return fs.ensureFile(initTestConfigJsonFile);
})
.then(() => {
return fs.outputJson(initTestConfigJsonFile, configTestConfigJson({
dbpathprefix: initTestPathDir,
settingsProp: {
logger: {
use_winston_logger: false,
},
},
}));
})
.then(() => {
// process.env.ENV = 'test';
configPeriodic = new periodicClass({});
configPeriodic.init({
app_root: initTestPathDir,
cli: true,
environment: 'test',
})
.then(done.bind(done, undefined))
.catch(done);
}).catch(done);
});
describe('getContentDBModelDir', () => {
it('should return the content model directory path', () => {
expect(config.getContentDBModelDir.call({
config: {
app_root: 'path/to/dir',
},
}, 'test')).to.eql('path/to/dir/content/config/databases/test/models');
});
});
describe('getDBModelDir', () => {
it('should return the content model directory path', () => {
expect(config.getDBModelDir.call({
config: {
app_root: 'path/to/dir',
},
}, { db_config_type: 'content', periodic_db_name: 'test', })).to.eql('path/to/dir/content/config/databases/test/models');
});
});
describe('assignLowkieModels', () => {
it('should resolve as true', () => {
const testModelDir = path.join(initTestPathDir, 'content/config/databases/standard/models');
const resolveSpy = sinon.spy();
const createSpy = sinon.spy();
const mockThis = {
dbs: new Map(),
};
const mockOptions = {
resolve: resolveSpy,
dboptions: {},
periodic_db_name: 'almTest',
db: {},
modelFiles: [],
};
config.assignLowkieModels.call(mockThis, mockOptions);
expect(resolveSpy.calledWith(true)).to.be.true;
});
it('should create lowkie models', () => {
const testModelDir = path.join(initTestPathDir, 'content/config/databases/standard/models');
const resolveSpy = sinon.spy();
const createSpy = sinon.spy();
const mockThis = {
dbs: new Map(),
datas: new Map(),
models: new Map(),
core: {
data: {
create: createSpy,
},
},
};
const mockOptions = {
resolve: resolveSpy,
dboptions: {},
periodic_db_name: 'default',
db: {},
modelFiles: fs.readdirSync(testModelDir),
modelDirPath: testModelDir,
};
// console.log(fs.readdirSync(path.join(initTestPathDir,'content/config/databases/standard/models')))
config.assignLowkieModels.call(mockThis, mockOptions);
expect(createSpy.called).to.be.true;
expect(mockThis.dbs.size).to.be.greaterThan(0);
expect(mockThis.datas.size).to.be.greaterThan(0);
expect(resolveSpy.calledWith(true)).to.be.true;
});
});
describe('assignMongooseModels', () => {
it('should resolve as true', () => {
const testModelDir = path.join(initTestPathDir, 'content/config/databases/standard/models');
const resolveSpy = sinon.spy();
const createSpy = sinon.spy();
const mockThis = {
dbs: new Map(),
};
const mockOptions = {
resolve: resolveSpy,
dboptions: {},
periodic_db_name: 'default',
db: {},
modelFiles: [],
};
config.assignMongooseModels.call(mockThis, mockOptions);
expect(resolveSpy.calledWith(true)).to.be.true;
});
it('should create mongoose models', () => {
const testModelDir = path.join(initTestPathDir, 'content/config/databases/standard/models');
const resolveSpy = sinon.spy();
const createSpy = sinon.spy();
const mockThis = {
dbs: new Map(),
datas: new Map(),
models: new Map(),
core: {
data: {
create: createSpy,
},
},
};
const mockOptions = {
resolve: resolveSpy,
periodic_db_name: 'default',
db: require('mongoose'),
dboptions: {},
modelFiles: fs.readdirSync(testModelDir),
modelDirPath: testModelDir,
};
// console.log(fs.readdirSync(path.join(initTestPathDir,'content/config/databases/standard/models')))
config.assignMongooseModels.call(mockThis, mockOptions);
expect(createSpy.called).to.be.true;
expect(mockThis.dbs.size).to.be.greaterThan(0);
expect(mockThis.datas.size).to.be.greaterThan(0);
expect(resolveSpy.calledWith(true)).to.be.true;
});
});
describe('assignSequelizeModels', () => {
it('should create sequelize models', (done) => {
const testModelDir = path.join(initTestPathDir, 'content/config/databases/standard/models');
const Sequelize = require('sequelize');
const dboptions = {
database: 'travis_ci_test',
username: '',
password: '',
connection_options: {
dialect: 'postgres',
port: 5432,
host: '127.0.0.1',
logging: false,
},
};
const sequelizeDB = new Sequelize(dboptions.database, dboptions.username, dboptions.password, dboptions.connection_options);
const resolveSpy = sinon.spy();
const createSpy = sinon.spy();
const mockThis = {
dbs: new Map(),
datas: new Map(),
models: new Map(),
core: {
data: {
create: createSpy,
},
},
config: {
debug:true,
},
};
const mockOptions = {
resolve: (val) => {
resolveSpy(val);
expect(createSpy.called).to.be.true;
expect(mockThis.dbs.size).to.be.greaterThan(0);
expect(mockThis.datas.size).to.be.greaterThan(0);
expect(resolveSpy.calledWith(true)).to.be.true;
done();
},
reject: done,
periodic_db_name: 'default',
dboptions: {},
db: sequelizeDB || {
sync: () => new Promise((resolve, reject) => { })
},
modelFiles: fs.readdirSync(testModelDir),
modelDirPath: testModelDir,
};
// console.log(fs.readdirSync(path.join(initTestPathDir,'content/config/databases/standard/models')))
try {
config.assignSequelizeModels.call(mockThis, mockOptions);
} catch (e) {
console.log('Cannot connect to Postgres')
done();
}
});
});
describe('connectLowkieDB', () => {
it('should handle errors', () => {
expect(config.connectLowkieDB()).to.eventually.be.rejected;
});
it('should connect to loki', () => {
const mockOptions = {
periodic_db_name: 'default',
db_config_type: 'content',
options: {
dbpath: path.join(initTestPathDir, 'content/config/settings/config_db.json'),
},
};
const mockThis = {};
expect(config.connectLowkieDB.call(mockThis, mockOptions)).to.eventually.be.fulfilled;
});
});
describe('connectMongooseDB', () => {
it('should handle errors', () => {
expect(config.connectMongooseDB()).to.eventually.be.rejected;
});
it('should connect to mongo', () => {
const mockOptions = {
periodic_db_name: 'default',
db_config_type: 'content',
options: {
url: 'mongodb://localhost:27017/config_db',
connection_options: {},
},
};
const mockThis = {
config: {
app_root: initTestPathDir,
},
};
expect(config.connectMongooseDB.call(mockThis, mockOptions)).to.eventually.be.fulfilled;
});
});
describe('connectSequelizeDB', () => {
it('should handle errors', () => {
expect(config.connectSequelizeDB()).to.eventually.be.rejected;
});
it('should connect to sql', () => {
const mockOptions = {
periodic_db_name: 'default',
db_config_type: 'content',
options: {
database: 'travis_ci_test',
username: '',
password: '',
connection_options: {
dialect: 'postgres',
port: 5432,
host: '127.0.0.1',
},
},
};
const mockThis = {
config: {
app_root: initTestPathDir,
},
};
expect(config.connectSequelizeDB.call(mockThis, mockOptions)).to.eventually.be.fulfilled;
});
});
describe('connectDB', () => {
it('should handle errors', () => {
expect(config.connectDB()).to.eventually.be.rejected;
});
it('should connect to loki', () => {
expect(config.connectDB({ db: 'lowkie', })).to.eventually.be.rejected;
});
it('should connect to mongo', () => {
expect(config.connectDB({ db: 'mongoose', })).to.eventually.be.rejected;
});
it('should connect to sql', () => {
expect(config.connectDB({ db: 'sequelize', })).to.eventually.be.rejected;
});
it('should resolve to true if no db specified', () => {
expect(config.connectDB({ db: 'other', })).to.eventually.eql(true);
});
});
describe('loadDatabases', () => {
it('should handle errors', () => {
expect(config.loadDatabases()).to.eventually.be.rejected;
});
it('should return true if no databases to connect', (done) => {
config.loadDatabases.call({
resources: {
databases: {
container: {},
extensions: {},
},
},
settings: {
databases: {},
},
})
.then(result => {
expect(result).to.be.true;
done();
})
.catch(done);
});
it('should return connected databases to from settings', (done) => {
config.loadDatabases.call({
resources: {
databases: {
container: {},
extensions: {},
},
},
settings: {
databases: {
test: {
db: 'other',
},
test2: {
db: 'other',
},
},
},
})
.then(results => {
expect(results.length).to.eql(2);
done();
})
.catch(done);
});
});
describe('loadExtensions', () => {
const extNotCompatible = extDoc({ 'periodic_compatibility': '11.0.0', });
describe('filterRequiredDependencies', () => {
it('should return true if dependency is not optional', () => {
expect(config.filterRequiredDependencies({ optional: false, })).to.be.true;
});
it('should return false if dependency is optional', () => {
expect(config.filterRequiredDependencies({ optional: true, })).to.be.false;
});
});
describe('mapForExtensionDependencyName', () => {
it('should return extension name', () => {
expect(config.mapForExtensionDependencyName({ extname: 'test', })).to.eql('test');
});
});
describe('checkForRequiredExtensions', () => {
it('should error if missing required extension', () => {
const errors = [];
const ext = {
name: 'test extension',
};
const mockThis = {
extensions: new Map(),
};
const mockOptions = {
errors,
reqExt: 'requiredExt',
ext,
};
config.checkForRequiredExtensions.call(mockThis, mockOptions);
expect(errors).to.have.length.greaterThan(0);
});
it('should not error if extension map has extension loaded', () => {
const errors = [];
const ext = {
name: 'requiredExt',
version: '1.0.0',
};
const mockThis = {
extensions: new Map(
[
[ext.name, ], ext,
]
),
};
const mockOptions = {
errors,
reqExt: 'requiredExt',
ext,
};
config.checkForRequiredExtensions.call(mockThis, mockOptions);
expect(errors.length).to.eql(0);
});
});
describe('checkExtensionDependencies', () => {
it('should error if extension is incompatible with periodic version', () => {
const errors = [];
const mockThis = {
settings: {
application: {
version: '10.0.0',
},
},
};
const mockOptions = {
errors,
ext: {
periodic_compatibility: '11.0.0',
},
};
config.checkExtensionDependencies.call(mockThis, mockOptions);
expect(errors).to.have.length.greaterThan(0);
});
it('should add valid extension to extensions map', () => {
const errors = [];
const ext = {
name: 'testExtension',
periodic_compatibility: '10.0.0',
};
const mockThis = {
settings: {
application: {
version: '10.0.0',
},
},
extensions: new Map(),
};
const mockOptions = {
errors,
ext,
};
config.checkExtensionDependencies.call(mockThis, mockOptions);
expect(mockThis.extensions.has(ext.name)).to.be.true;
expect(mockThis.extensions.get(ext.name)).to.eql(ext);
expect(errors.length).to.eql(0);
});
});
describe('loadExtensions functionality', () => {
it('should handle errors', () => {
expect(config.loadExtensions()).to.eventually.be.rejected;
});
it('should return true if there are no extensions', (done) => {
const mockThis = {
settings: {
application: {
exit_on_invalid_extensions: false,
},
},
crud: {
ext: {
list: () => {
return new Promise((resolve, reject) => {
resolve([]);
});
},
},
},
};
config.loadExtensions.call(mockThis)
.then(result => {
expect(result).to.be.true;
done();
})
.catch(done);
});
it('should return reject on error if settings is set ', (done) => {
const errorSpy = sinon.spy();
const mockThis = {
settings: {
application: {
version: '10.0.0',
exit_on_invalid_extensions: true,
},
},
extensions: new Set(),
crud: {
ext: {
list: () => {
return new Promise((resolve, reject) => {
resolve([extNotCompatible, ]);
});
},
},
},
logger: {
error: errorSpy,
},
};
config.loadExtensions.call(mockThis)
.then(result => {
done(new Error('Should reject if invalid extension config'));
})
.catch(e => {
expect(errorSpy.called).to.be.true;
expect(e.message).to.eql('Invalid extension configuration');
done();
});
});
});
});
after('remove config test periodic dir', (done) => {
fs.remove(initTestPathDir)
.then(() => {
done();
}).catch(done);
});
});