Commit 208f3854 authored by Dang Dien PHAN's avatar Dang Dien PHAN

#7 - Use Docker pipeline

parent a5849afc
before_script:
- . ~/.nvm/nvm.sh && nvm use 8
image: linagora/node-test-base:8
stages:
- test
......@@ -8,17 +7,19 @@ stages:
test:
stage: test
tags:
- shell
- online.net
- mongo
- redis
- docker
services:
- mongo:3.4
- elasticsearch:2.4
- redis:3
- rabbitmq:3.6
script:
- npm i
- npm update
- bower i
- bower i --allow-root
- grunt --chunk=1 --ci
.deploy_dev:
deploy_dev:
stage: deploy_dev
tags:
- dev.open-paas.org
......@@ -32,7 +33,7 @@ test:
- cd /srv/${CI_PROJECT_NAME}
- git fetch --all
- git checkout ${CI_COMMIT_SHA}
- npm install --ignore-scripts --production
- npm install --production
- npm update --production
- npm prune
- bower install --production
......
'use strict';
const conf_path = './test/config/';
const servers = require(conf_path + 'servers-conf');
const GruntfileUtils = require('./tasks/utils/Gruntfile-utils');
const timeGrunt = require('time-grunt');
module.exports = function(grunt) {
timeGrunt(grunt);
const gruntfileUtils = new GruntfileUtils(grunt, servers);
const runGrunt = gruntfileUtils.runGrunt();
const shell = gruntfileUtils.shell();
const command = gruntfileUtils.command();
grunt.initConfig({
eslint: {
options: {
......@@ -53,33 +45,6 @@ module.exports = function(grunt) {
}
},
shell: {
mongo: shell.newShell(command.mongo(false), new RegExp('connections on port ' + servers.mongodb.port), 'MongoDB server is started.'),
redis: shell.newShell(command.redis, /on port/, 'Redis server is started')
},
run_grunt: {
midway_backend: runGrunt.newProcess(['test-midway-backend']),
unit_backend: runGrunt.newProcess(['test-unit-backend']),
unit_frontend: runGrunt.newProcess(['test-frontend'])
},
puglint: {
all: {
options: {
config: {
disallowAttributeInterpolation: true,
disallowLegacyMixinCall: true,
validateExtensions: true,
validateIndentation: 2
}
},
src: [
'frontend/**/*.pug'
]
}
},
i18n_checker: {
all: {
options: {
......@@ -101,13 +66,63 @@ module.exports = function(grunt) {
'key-trimmed',
'no-duplicate-among-modules',
'no-duplicate-with-core',
'no-untranslated-key',
'valid-json-file'
]
}
}
}
}
},
puglint: {
all: {
options: {
config: {
disallowAttributeInterpolation: true,
disallowLegacyMixinCall: true,
validateExtensions: true,
validateIndentation: 2
}
},
src: [
'frontend/**/*.pug'
]
}
},
splitfiles: {
options: {
chunk: 1
},
midway: {
options: {
common: ['test/midway-backend/all.js'],
target: 'mochacli:midway'
},
files: {
src: ['test/midway-backend/**/*.js']
}
}
},
mochacli: {
options: {
require: ['chai', 'mockery'],
reporter: 'spec',
timeout: process.env.TEST_TIMEOUT || 5000
},
backend: {
options: {
files: ['test/unit-backend/all.js', grunt.option('test') || 'test/unit-backend/**/*.js']
}
}
},
karma: {
unit: {
configFile: './test/config/karma.conf.js',
browsers: ['PhantomJS']
}
}
});
grunt.loadTasks('tasks');
......@@ -119,27 +134,17 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-shell-spawn');
grunt.loadNpmTasks('grunt-continue');
grunt.loadNpmTasks('grunt-run-grunt');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-wait-server');
grunt.loadNpmTasks('@linagora/grunt-i18n-checker');
grunt.loadNpmTasks('grunt-puglint');
grunt.loadNpmTasks('grunt-i18n-checker');
grunt.registerTask('pug-linter', 'Check the pug/jade files', ['puglint:all']);
grunt.registerTask('linters', 'Check code for lint', ['eslint:all', 'lint_pattern:all', 'lint_pattern:css', 'pug-linter', 'i18n']);
grunt.registerTask('i18n', 'Check the translation files', ['i18n_checker']);
grunt.registerTask('pug-linter', 'Check the pug/jade files', ['puglint:all']);
grunt.registerTask('linters', 'Check code for lint', ['eslint:all', 'lint_pattern:all', 'lint_pattern:css', 'i18n', 'pug-linter']);
grunt.registerTask('linters-dev', 'Check changed files for lint', ['prepare-quick-lint', 'eslint:quick', 'lint_pattern:quick']);
grunt.registerTask('spawn-servers', 'spawn servers', ['shell:mongo', 'shell:redis']);
grunt.registerTask('kill-servers', 'kill servers', ['shell:mongo:kill', 'shell:redis:kill']);
grunt.registerTask('setup-environment', 'create temp folders and files for tests', gruntfileUtils.setupEnvironment());
grunt.registerTask('clean-environment', 'remove temp folder for tests', gruntfileUtils.cleanEnvironment());
grunt.registerTask('setup-servers', ['spawn-servers', 'continue:on']);
grunt.registerTask('test-midway-backend', ['setup-environment', 'setup-servers', 'run_grunt:midway_backend', 'kill-servers', 'clean-environment']);
grunt.registerTask('test-unit-backend', 'Test backend code', ['run_grunt:unit_backend']);
grunt.registerTask('test-unit-frontend', 'Test frontend code', ['run_grunt:unit_frontend']);
grunt.registerTask('test-midway-backend', ['splitfiles:midway']);
grunt.registerTask('test-unit-backend', 'Test backend code', ['mochacli:backend']);
grunt.registerTask('test-unit-frontend', 'Test frontend code', ['karma:unit']);
grunt.registerTask('test', ['linters', 'test-unit-frontend', 'test-unit-backend', 'test-midway-backend']);
grunt.registerTask('default', ['test']);
};
......@@ -4,6 +4,9 @@
"description": "OpenPaaS Module sample to create new ones",
"main": "index.js",
"devDependencies": {
"@linagora/grunt-i18n-checker": "2.0.5",
"@linagora/karma-ng-jade2module-preprocessor": "0.5.3",
"@linagora/i18n-checker": "2.0.3",
"chai": "3.5.0",
"chai-as-promised": "5.3.0",
"chai-shallow-deep-equal": "1.4.0",
......@@ -12,28 +15,21 @@
"eslint-config-linagora-esn": "1.0.2",
"eslint-plugin-import": "1.16.0",
"grunt": "1.0.1",
"grunt-continue": "0.1.0",
"grunt-contrib-concat": "1.0.1",
"grunt-contrib-jshint": "1.1.0",
"grunt-contrib-watch": "1.0.0",
"grunt-eslint": "19.0.0",
"grunt-i18n-checker": "linagora/grunt-i18n-checker#v2.0.0",
"grunt-karma": "2.0.0",
"grunt-lint-pattern": "linagora/grunt-lint-pattern#7c6f4e1bc98c2851fec2714e115ac33e1b064ca7",
"grunt-lint-pattern": "0.1.4",
"grunt-mocha-cli": "3.0.0",
"grunt-puglint": "1.0.0",
"grunt-contrib-clean": "1.0.0",
"grunt-run": "0.6.0",
"grunt-run-grunt": "linagora/grunt-run-grunt.git",
"grunt-shell": "2.1.0",
"grunt-shell-spawn": "0.3.10",
"grunt-wait-server": "0.3.0",
"karma": "1.7.1",
"karma-chrome-launcher": "2.0.0",
"karma-coverage": "1.1.1",
"karma-firefox-launcher": "1.0.0",
"karma-mocha": "1.1.1",
"karma-ng-jade2module-preprocessor": "linagora/karma-ng-jade2module-preprocessor#9fb962530b01",
"karma-phantomjs-launcher": "1.0.2",
"karma-spec-reporter": "0.0.26",
"linagora-rse": "linagora/openpaas-esn#master",
......@@ -46,8 +42,7 @@
"sinon-chai": "2.8.0",
"socket.io": "1.2.1",
"supertest": "2.0.0",
"time-grunt": "1.4.0",
"i18n-checker": "linagora/i18n-checker#v2.0.0"
"time-grunt": "1.4.0"
},
"scripts": {
"test": "grunt test",
......
'use strict';
const util = require('util');
const fs = require('fs-extra');
const path = require('path');
function _args(grunt) {
const opts = ['test', 'chunk', 'ci', 'reporter'];
const args = {};
opts.forEach(optName => {
const opt = grunt.option(optName);
if (opt) {
args[optName] = String(opt);
}
});
return args;
}
function _taskEndIfMatch(grunt, regexSuccess, infoSuccess, regexFailed) {
let taskIsDone = false;
return function(chunk, done) {
if (taskIsDone) { return; }
if (regexSuccess || regexFailed) {
done = done || grunt.task.current.async();
if (regexSuccess && regexSuccess.test(String(chunk))) {
taskIsDone = true;
grunt.log.oklns(infoSuccess);
done(true);
} else if (regexFailed && regexFailed.test(String(chunk))) {
taskIsDone = true;
grunt.log.error(chunk);
done(false);
}
}
};
}
class GruntfileUtils {
constructor(grunt, servers) {
this.grunt = grunt;
this.servers = servers;
this.args = _args(grunt);
}
command() {
const servers = this.servers;
const commandObject = {};
commandObject.redis = util.format('%s --port %s %s %s',
servers.redis.cmd,
(servers.redis.port ? servers.redis.port : '23457'),
(servers.redis.pwd ? '--requirepass' + servers.redis.pwd : ''),
(servers.redis.conf_file ? servers.redis.conf_file : ''));
commandObject.mongo = function(repl) {
var replset = repl ?
util.format('--replSet \'%s\' --smallfiles --oplogSize 128', servers.mongodb.replicat_set_name) :
'--nojournal';
return util.format('%s --nounixsocket --dbpath %s --port %s %s',
servers.mongodb.cmd,
servers.mongodb.dbpath,
(servers.mongodb.port ? servers.mongodb.port : '23456'),
replset);
};
return commandObject;
}
shell() {
const grunt = this.grunt;
return {
newShell(command, regex, info) {
return {
command: command,
options: {
async: false,
stdout: _taskEndIfMatch(grunt, regex, info),
stderr: grunt.log.error,
canKill: true
}
};
}
};
}
runGrunt() {
const grunt = this.grunt;
const args = this.args;
function _process(res) {
grunt.config.set('esn.tests.success', !res.fail);
grunt.log.writeln(res.fail ? 'failed' : 'succeeded');
}
return {
newProcess(task) {
return {
options: {
log: true,
stdout: grunt.log.write,
stderr: grunt.log.error,
args: args,
process: _process,
task: task
},
src: ['Gruntfile-tests.js']
};
}
};
}
setupEnvironment() {
const servers = this.servers;
return function() {
try {
fs.mkdirsSync(servers.mongodb.dbpath);
fs.mkdirsSync(servers.tmp);
} catch (err) {
throw err;
}
};
}
cleanEnvironment() {
const grunt = this.grunt;
const servers = this.servers;
return function() {
function _removeAllFilesInDirectory(directory) {
let files;
try {
files = fs.readdirSync(directory);
} catch (err) {
console.error(err);
return;
}
for (let i = 0; i < files.length; i++) {
const filePath = directory + '/' + files[i];
if (fs.statSync(filePath).isFile()) {
fs.unlinkSync(filePath);
} else {
_removeAllFilesInDirectory(filePath);
}
}
try {
fs.rmdirSync(directory);
} catch (e) {
console.error(e);
}
}
const testsFailed = !grunt.config.get('esn.tests.success');
const applog = path.join(servers.tmp, 'application.log');
if (testsFailed && fs.existsSync(applog)) {
fs.copySync(applog, 'application.log');
}
_removeAllFilesInDirectory(servers.tmp);
if (testsFailed) {
grunt.log.writeln('Tests failure');
grunt.fail.fatal('error', 3);
}
const done = this.async();
done(true);
};
}
}
module.exports = GruntfileUtils;
{
"connectionString": "mongodb://mongo/tests",
"connectionOptions": {
"auto_reconnect": false
}
}
{
"webserver": {
"enabled": true,
"ip": "127.0.0.1",
"ipv6": "::1",
"port": 8081,
"virtualhosts": [],
"startupBufferTimeout": 5000
},
"wsserver": {
"enabled": false,
"port": 8081
},
"log": {
"file": {
"enabled": false
},
"console": {
"enabled": true,
"level": "error"
}
},
"auth": {
"strategies": ["mongo"],
"apiStrategies": ["basic-mongo"]
},
"core": {
"config": {
"db": "db.json"
}
}
}
......@@ -43,7 +43,7 @@ module.exports = function(config) {
'karma-mocha',
'karma-coverage',
'karma-spec-reporter',
'karma-ng-jade2module-preprocessor'
'@linagora/karma-ng-jade2module-preprocessor'
],
coverageReporter: { type: 'text', dir: '/tmp' },
......
'use strict';
const DEFAULT_PORTS = {
express: 23455,
mongo: 23456,
redis: 23457
express: 23455
};
const tmp = 'tmp';
const host = process.env.HOSTNAME || process.env.DOCKER_HOST || 'localhost';
const dbName = 'tests';
const mongoPort = process.env.PORT_MONGODB || DEFAULT_PORTS.mongo;
module.exports = {
tmp,
default_ports: DEFAULT_PORTS,
host,
host: process.env.HOSTNAME || process.env.DOCKER_HOST || 'localhost',
express: {
port: process.env.PORT_EXPRESS || DEFAULT_PORTS.express
},
redis: {
cmd: process.env.CMD_REDIS || 'redis-server',
port: process.env.PORT_REDIS || DEFAULT_PORTS.redis,
conf_file: '',
log_path: '',
pwd: ''
host: 'redis',
port: 6379,
url: 'redis://redis:6379'
},
mongodb: {
cmd: process.env.CMD_MONGODB || 'mongod',
port: mongoPort,
interval_replica_set: process.env.MONGODB_INTERVAL_REPLICA_SET || 1000,
tries_replica_set: process.env.MONGODB_TRIES_REPLICA_SET || 20,
connectionString: 'mongodb://' + host + ':' + mongoPort + '/' + dbName,
replicat_set_name: 'rs',
dbname: dbName,
dbpath: tmp + '/mongo/',
logpath: ''
host: 'mongo',
port: 27017,
connectionString: 'mongodb://mongo/tests'
},
elasticsearch: {
host: 'elasticsearch',
port: 9200
},
rabbitmq: {
host: 'rabbitmq',
port: 5672,
url: 'amqp://rabbitmq:5672'
}
};
'use strict';
const mockery = require('mockery');
/* eslint-disable no-console, no-process-env */
const chai = require('chai');
const path = require('path');
const fs = require('fs-extra');
const mongoose = require('mongoose');
const testConfig = require('../config/servers-conf');
const basePath = path.resolve(__dirname + '/../../node_modules/linagora-rse');
const tmpPath = path.resolve(__dirname + '/../..', testConfig.tmp);
const backendPath = path.normalize(__dirname + '/../../backend');
const host = testConfig.host;
const MODULE_NAME = 'awesome.module.seed';
const MODULE_NAME = 'linagora.esn.seed';
let rse;
before(function(done) {
mongoose.Promise = require('q').Promise;
chai.use(require('chai-shallow-deep-equal'));
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
......@@ -23,70 +18,38 @@ before(function(done) {
this.testEnv = {
serversConfig: testConfig,
basePath: basePath,
tmp: tmpPath,
backendPath: backendPath,
fixtures: path.resolve(basePath, 'test/midway-backend/fixtures'),
mongoUrl: 'mongodb://' + host + ':' + testConfig.mongodb.port + '/' + testConfig.mongodb.dbname,
writeDBConfigFile() {
fs.writeFileSync(tmpPath + '/db.json', JSON.stringify({connectionString: 'mongodb://' + host + ':' + testConfig.mongodb.port + '/' + testConfig.mongodb.dbname, connectionOptions: {auto_reconnect: false}}));
},
removeDBConfigFile() {
fs.unlinkSync(tmpPath + '/db.json');
},
mongoUrl: testConfig.mongodb.connectionString,
initCore(callback) {
mongoose.Promise = require('q').Promise;
rse.core.init(() => { callback && process.nextTick(callback); });
}
};
process.env.NODE_CONFIG = this.testEnv.tmp;
process.env.NODE_CONFIG = 'test/config';
process.env.NODE_ENV = 'test';
fs.copySync(this.testEnv.fixtures + '/default.mongoAuth.json', this.testEnv.tmp + '/default.json');
process.env.REDIS_HOST = 'redis';
process.env.REDIS_PORT = 6379;
process.env.AMQP_HOST = 'rabbitmq';
process.env.ES_HOST = 'elasticsearch';
rse = require('linagora-rse');
this.helpers = {};
this.testEnv.core = rse.core;
this.testEnv.moduleManager = rse.moduleManager;
rse.test.helpers(this.helpers, this.testEnv);
rse.test.moduleHelpers(this.helpers, this.testEnv);
rse.test.apiHelpers(this.helpers, this.testEnv);
const manager = this.testEnv.moduleManager.manager;
const nodeModulesPath = path.normalize(
path.join(__dirname, '../../node_modules/')
);
const nodeModulesLoader = manager.loaders.filesystem(nodeModulesPath, true);
const loader = manager.loaders.code(require('../../index.js'), true);
manager.appendLoader(nodeModulesLoader);
manager.appendLoader(loader);
loader.load(MODULE_NAME, done);
});
// https://github.com/mfncooper/mockery/issues/34
before(function() {
require('canvas');
require('ursa');
});
after(function() {
try {
fs.unlinkSync(this.testEnv.tmp + '/default.json');
} catch (e) {
console.error(e);
}
delete process.env.NODE_CONFIG;
delete process.env.NODE_ENV;
});
beforeEach(function() {
mockery.enable({warnOnReplace: false, warnOnUnregistered: false, useCleanCache: true});
this.testEnv.writeDBConfigFile();
});
afterEach(function() {
try {
this.testEnv.removeDBConfigFile();
} catch (e) {
console.error(e);
}
mockery.resetCache();
mockery.deregisterAll();
mockery.disable();
loader.load(MODULE_NAME, done);
});
......@@ -35,7 +35,10 @@ describe('The example API', function() {
});
afterEach(function(done) {
this.helpers.mongo.dropDatabase(done);
this.helpers.mongo.dropDatabase(err => {
if (err) return done(err);
this.testEnv.core.db.mongo.mongoose.connection.close(done);
});
});
describe('GET /example', function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment