diff --git a/config.json.example b/config.json.example
index 3e586b5684bc2749e8eee38f4c4630f10fa62a8b..ea9bd2f3a7c826ed36999cb360b748801d1445ef 100644
--- a/config.json.example
+++ b/config.json.example
@@ -5,7 +5,7 @@
         "ip": "127.0.0.1",
         "debug" : true,
         "monetdb": {
-            "host": "simcaqdb1",
+            "host": "simcaqdb3.c3sl.ufpr.br",
             "port": 50000,
             "dbname": "simcaq_dev",
             "user": "monetdb",
@@ -28,7 +28,7 @@
         "ip": "127.0.0.1",
         "debug" : true,
         "monetdb": {
-            "host": "simcaqdb1",
+            "host": "simcaqdb3.c3sl.ufpr.br",
             "port": 50000,
             "dbname": "simcaq_dev",
             "user": "monetdb",
@@ -51,7 +51,7 @@
         "ip": "127.0.0.1",
         "debug" : false,
         "monetdb": {
-            "host": "simcaqdb1",
+            "host": "simcaqdb3.c3sl.ufpr.br",
             "port": 50000,
             "dbname": "simcaq_dev",
             "user": "monetdb",
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index e732dc6b630cb7da241d00fdf1ba451fc6124d62..2ff461ffc69e431cf02358587d59f2f80391c95f 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -74,12 +74,17 @@ gulp.task('pre-test', () => {
 
 gulp.task('test', ['pre-test'], () => {
     process.chdir('build');
-    gulp.src('test/test.js', {read: false})
+    gulp.src(['test/**/*.js'], {read: false})
     .pipe(mocha({timeout: 15000}))
     .pipe(istanbul.writeReports())
     .pipe(istanbul.enforceThresholds({
         thresholds: {
-            global: 80
+            global: {
+                statements: 80,
+                branches: 75,
+                lines: 80,
+                functions: 80
+            }
         }
     }))
     .on('error', () => {
diff --git a/package.json b/package.json
index d923ed1f1a30bd1b7753d665a08407233a5bb3e0..9173c5505a5e0eadbfe3db5da32281e586be927f 100644
--- a/package.json
+++ b/package.json
@@ -49,11 +49,11 @@
     "browserify": "^13.1.0",
     "chai-xml": "^0.3.1",
     "docdash": "^0.4.0",
-    "eslint": "^3.3.1",
+    "eslint": "^3.7.1",
     "eslint-config-airbnb": "^13.0.0",
     "eslint-plugin-import": "^2.2.0",
     "eslint-plugin-jsx-a11y": "^2.2.3",
-    "eslint-plugin-react": "^6.1.1",
+    "eslint-plugin-react": "^6.4.0",
     "gulp": "^3.9.1",
     "gulp-babel": "^6.1.2",
     "gulp-cli": "^1.2.2",
diff --git a/src/libs/models/user.js b/src/libs/models/user.js
index 83315b8238e97ce11daf02a8234824ff660f3d7b..554fabf05b5816c0a13ecc825a682dcb141e803c 100644
--- a/src/libs/models/user.js
+++ b/src/libs/models/user.js
@@ -64,7 +64,7 @@ UserSchema.pre('save', function (next) {
             if (err) {
                 return next(err);
             }
-            bcrypt.hash(user.password, salt, function (err, hash) {
+            bcrypt.hash(user.password, salt, null, function (err, hash) {
                 if (err) {
                     return next(err);
                 }
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 2c259bab8c800180d240d20a525b0c908868422e..2c29a24680987a9b6c572cf5fa4ba86bc0b0c83c 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -18,6 +18,8 @@ const city = require('./city');
 
 const school = require('./school');
 
+const location = require('./location');
+
 const simulation = require('./simulation');
 
 const user = require('./user');
@@ -27,7 +29,6 @@ api.get('/', (req, res) => {
 });
 
 // mount API routes
-
 api.use('/user', user);
 api.use('/simulation', simulation);
 api.use('/enrollment', cache('1 day'), enrollment);
@@ -35,5 +36,6 @@ api.use('/state', cache('15 day'), state);
 api.use('/region', cache('15 day'), region);
 api.use('/city', cache('15 day'), city);
 api.use('/school', cache('15 day'), school);
+api.use('/location', cache('1 day'), location);
 
 module.exports = api;
diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js
index d963287567363544f145ecef506dcf934f669767..3bccfebf6fffc1153b553f8ebe11bf00d934d033 100644
--- a/src/libs/routes/city.js
+++ b/src/libs/routes/city.js
@@ -12,20 +12,33 @@ const response = require(`${libs}/middlewares/response`);
 
 // Return all cities
 cityApp.get('/', (req, res, next) => {
-    req.sql.from('municipio');
+    req.sql.from('municipio')
+        .field('pk_cod_ibge', 'pk_municipio_id')
+        .field('nome')
+        .field('pk_cod_ibge', 'codigo_ibge')
+        .field('fk_estado_id');
     next();
 }, query, response('city'));
 
 // Return a specific city by it's id
 cityApp.get('/:id', (req, res, next) => {
     req.sql.from('municipio')
+        .field('pk_cod_ibge', 'pk_municipio_id')
+        .field('nome', 'nome')
+        .field('pk_cod_ibge', 'codigo_ibge')
+        .field('fk_estado_id')
         .where('pk_cod_ibge = ?', parseInt(req.params.id, 10));
     next();
 }, query, response('city'));
 
 // Return a specific city by it's IBGE code
+// TODO: this route becomes obsolete in the new schema, deprecate it
 cityApp.get('/ibge/:id', (req, res, next) => {
     req.sql.from('municipio')
+        .field('pk_cod_ibge', 'pk_municipio_id')
+        .field('nome')
+        .field('fk_estado_id')
+        .field('pk_cod_ibge', 'codigo_ibge')
         .where('pk_cod_ibge = ?', parseInt(req.params.id, 10));
     next();
 }, query, response('city'));
@@ -33,6 +46,10 @@ cityApp.get('/ibge/:id', (req, res, next) => {
 // Return all the cities from a specific state
 cityApp.get('/state/:id', (req, res, next) => {
     req.sql.from('municipio')
+        .field('pk_cod_ibge', 'pk_municipio_id')
+        .field('nome')
+        .field('pk_cod_ibge', 'codigo_ibge')
+        .field('fk_estado_id')
         .where('fk_estado_id = ?', parseInt(req.params.id, 10));
     next();
 }, query, response('city'));
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index 3e878e7f23b2d038cf217147f19c28d34a246e4e..a20b24bc694cbd00d2e1f40cc8df38dc6100cc04 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -16,17 +16,25 @@ const parseParams = require(`${libs}/middlewares/parseParams`);
 
 // **Temporary** solution to add where clauses that are common to all requests
 
-
 // Complete range of the enrollments dataset.
 // Returns a tuple of start and ending years of the complete enrollments dataset.
 enrollmentApp.get('/year_range', (req, res, next) => {
-    req.sql.from('turma')
+    req.sql = squel.select()
+        .from('turma')
         .field('MIN(turma.ano_censo)', 'start_year')
         .field('MAX(turma.ano_censo)', 'end_year');
 
     next();
 }, query, response('range'));
 
+enrollmentApp.get('/location', (req, res, next) => {
+    req.sql = squel.select()
+        .field('pk_localizacao_id', 'location_id')
+        .field('descricao', 'description')
+        .from('localizacao');
+    next();
+}, query, response('location'));
+
 // Returns all educational levels avaible
 enrollmentApp.get('/education_level', (req, res, next) => {
     req.sql.from('etapa_ensino')
@@ -38,7 +46,8 @@ enrollmentApp.get('/education_level', (req, res, next) => {
 
 // Returns all adm dependencies
 enrollmentApp.get('/adm_dependency', (req, res, next) => {
-    req.sql.from('dependencia_adm')
+    req.sql = squel.select()
+        .from('dependencia_adm')
         .field('pk_dependencia_adm_id', 'id')
         .field('nome', 'name');
 
@@ -68,38 +77,51 @@ enrollmentApp.use('/', parseParams('filter', [
     log.debug(req.filter);
     log.debug(req.dims);
 
+    //applyJoins(req.sql, req.filter, req.dims);
+
     // Do the joins
     if(typeof req.filter.adm_dependency !== 'undefined'
         || typeof req.dims.adm_dependency !== 'undefined') {
-        req.sql.join('dependencia_adm', null, 'fk_dependencia_adm_id=dependencia_adm.pk_dependencia_adm_id');
+        req.sql.join('dependencia_adm', null,
+            'fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id');
     }
 
     if(typeof req.filter.education_level !== 'undefined'
         || typeof req.dims.education_level !== 'undefined') {
-        req.sql.join('etapa_ensino', null, 'fk_etapa_ensino_id=etapa_ensino.pk_etapa_ensino_id');
+        req.sql.join('etapa_ensino', null,
+            'turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id');
     }
 
     if(typeof req.filter.region !== 'undefined'
         || typeof req.dims.region !== 'undefined') {
-            req.sql.join('regiao', null, 'fk_regiao_id=regiao.pk_regiao_id');
+            req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
+                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id')
+                .join('regiao', null, 'estado.fk_regiao_id = regiao.pk_regiao_id');
     }
 
-    if(typeof req.filter.state !== 'undefined'
-        || typeof req.dims.state !== 'undefined') {
-            req.sql.join('estado', null, 'fk_estado_id=estado.pk_estado_id');
+    if((typeof req.filter.state !== 'undefined'
+        || typeof req.dims.state !== 'undefined')
+        && (typeof req.filter.region === 'undefined'
+        && typeof req.dims.region === 'undefined')) {
+            req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
+                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id');
     }
 
-    if(typeof req.filter.city !== 'undefined'
-        || typeof req.dims.city !== 'undefined') {
-        req.sql.join('municipio', null, 'fk_municipio_id=municipio.pk_cod_ibge');
+    if((typeof req.filter.city !== 'undefined'
+        || typeof req.dims.city !== 'undefined')
+        && (typeof req.filter.state === 'undefined'
+        && typeof req.dims.state === 'undefined')
+        && (typeof req.filter.region === 'undefined'
+        && typeof req.dims.region === 'undefined')) {
+        req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge');
     }
 
-    if(typeof req.dims.school !== 'undefined') {
-        req.sql.join('escola', null, 'turma.cod_entidade=escola.cod_entidade');
+    if(typeof req.filter.location !== 'undefined' || typeof req.dims.location !== 'undefined') {
+        req.sql.join('localizacao', null, 'fk_localizacao_id = localizacao.pk_localizacao_id')
     }
 
-    if(typeof req.dims.location !== 'undefined') {
-        req.sql.join('localizacao', null, 'turma.id_localizacao=localizacao.pk_localizacao_id')
+    if(typeof req.dims.school !== 'undefined') {
+        req.sql.join('escola', null, 'turma.cod_entidade = escola.cod_entidade');
     }
 
     // Dimensions (add fields)
@@ -128,8 +150,17 @@ enrollmentApp.use('/', parseParams('filter', [
             .order('municipio.nome');
     }
 
+    /**
+     * TODO: field nome_entidade is not present in the new schema, remove this part
+    if(typeof req.dims.school !== 'undefined') {
+        req.sql.field('escola.nome_entidade', 'school_name')
+            .group('escola.nome_entidade')
+            .order('escola.nome_entidade');
+    }
+    */
+
     if(typeof req.dims.school !== 'undefined') {
-        req.sql.field('escola.cod_entidade', 'school_name')
+        req.sql.field('escola.cod_entidade', 'school_code')
             .group('escola.cod_entidade')
             .order('escola.cod_entidade');
     }
@@ -156,39 +187,39 @@ enrollmentApp.use('/', parseParams('filter', [
     // Filter (add where)
 
     if (typeof req.filter.min_year !== 'undefined') {
-        req.sql.where('turma.ano_censo>=?', parseInt(req.filter.min_year, 10));
+        req.sql.where('turma.ano_censo >= ?', parseInt(req.filter.min_year, 10));
     }
 
     if (typeof req.filter.max_year !== 'undefined') {
-        req.sql.where('turma.ano_censo<=?', parseInt(req.filter.max_year, 10));
+        req.sql.where('turma.ano_censo <= ?', parseInt(req.filter.max_year, 10));
     }
 
     if (typeof req.filter.adm_dependency !== 'undefined') {
-        req.sql.where('pk_dependencia_adm_id=?', parseInt(req.filter.adm_dependency, 10));
+        req.sql.where('pk_dependencia_adm_id = ?', parseInt(req.filter.adm_dependency, 10));
     }
 
     if (typeof req.filter.location !== 'undefined') {
-        req.sql.where('turma.id_localizacao=?', parseInt(req.filter.location, 10));
+        req.sql.where('turma.fk_localizacao_id = ?', parseInt(req.filter.location, 10));
     }
 
     if (typeof req.filter.education_level !== 'undefined') {
-        req.sql.where('pk_etapa_ensino_id=?', parseInt(req.filter.education_level, 10));
+        req.sql.where('pk_etapa_ensino_id = ?', parseInt(req.filter.education_level, 10));
     }
 
     if (typeof req.filter.region !== 'undefined') {
-        req.sql.where('pk_regiao_id=?', parseInt(req.filter.region, 10));
+        req.sql.where('pk_regiao_id = ?', parseInt(req.filter.region, 10));
     }
 
     if (typeof req.filter.state !== 'undefined') {
-        req.sql.where('pk_estado_id=?', parseInt(req.filter.state, 10));
+        req.sql.where('pk_estado_id = ?', parseInt(req.filter.state, 10));
     }
 
     if (typeof req.filter.city !== 'undefined') {
-        req.sql.where('turma.fk_municipio_id=?', parseInt(req.filter.city, 10));
+        req.sql.where('turma.fk_municipio_id = ?', parseInt(req.filter.city, 10));
     }
 
     if (typeof req.filter.school !== 'undefined') {
-        req.sql.where('turma.fk_escola_id=?', parseInt(req.filter.school, 10));
+        req.sql.where('turma.cod_entidade = ?', parseInt(req.filter.school, 10));
     }
     log.debug(req.sql.toParam());
     next();
diff --git a/src/libs/routes/location.js b/src/libs/routes/location.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5476f5ea451876aa2e4c6ad0d4fe67a5b214879
--- /dev/null
+++ b/src/libs/routes/location.js
@@ -0,0 +1,1279 @@
+const express = require('express');
+
+const libs = `${process.cwd()}/libs`;
+
+const squel = require('squel');
+
+const log = require(`${libs}/log`)(module);
+
+const query = require(`${libs}/middlewares/query`);
+
+const sqlQuery = require(`${libs}/db/query_exec`);
+
+const response = require(`${libs}/middlewares/response`);
+
+const locationApp = express();
+
+function locationIdToStr(locationId) {
+    let locationStr = 'Total';
+    switch(locationId) {
+        case 1:
+            locationStr = 'Urbana';                         break;
+        case 2:
+            locationStr = 'Rural';                          break;
+        case 3:
+            locationStr = 'Área de assentamento';           break;
+        case 4:
+            locationStr = 'Terra indígena';                 break;
+        case 5:
+            locationStr = 'Área remanescente de quilombos'; break;
+        case 6:
+            locationStr = 'Unidade de uso sustentável';     break;
+
+    }
+    return locationStr;
+}
+
+function schoolYearIdToStr(schoolYearId)
+{
+    let schoolYearStr;
+    switch(schoolYearId) {
+        case 11:
+            schoolYearStr = 'Creche';
+            break;
+        case 21:
+            schoolYearStr = 'Pré-escola';
+            break;
+        case 31:
+            schoolYearStr = '1 Ano';
+            break;
+        case 32:
+            schoolYearStr = '2 Ano - 1 Serie';
+            break;
+        case 33:
+            schoolYearStr = '3 Ano - 2 Serie';
+            break;
+        case 34:
+            schoolYearStr = '4 Ano - 3 Serie';
+            break;
+        case 35:
+            schoolYearStr = '5 Ano - 4 Serie';
+            break;
+        case 41:
+            schoolYearStr = '6 Ano - 5 Serie';
+            break;
+        case 42:
+            schoolYearStr = '7 Ano - 6 Serie';
+            break;
+        case 43:
+            schoolYearStr = '8 Ano - 7 Serie';
+            break;
+        case 44:
+            schoolYearStr = '9 Ano - 8 Serie';
+            break;
+        case 51:
+            schoolYearStr = '1 Ano'; // equivalent to 'EM 1 Série'
+            break;
+        case 52:
+            schoolYearStr = '2 Ano'; // equivalent to 'EM 2 Série'
+            break;
+        case 53:
+            schoolYearStr = '3 Ano'; // equivalent to 'EM 3 Série'
+            break;
+        case 54:
+            schoolYearStr = '4 Ano'; // equivalent to 'EM 4 Série'
+            break;
+        case 61:
+            schoolYearStr = 'EJA AI';
+            break;
+        case 62:
+            schoolYearStr = 'EJA AF';
+            break;
+        case 63:
+            schoolYearStr = 'EJA EM';
+            break;
+        case 64:
+            schoolYearStr = 'EJA semi-presencial';
+            break;
+        case 71:
+            schoolYearStr = 'EP';
+            break;
+        case 81:
+            schoolYearStr = 'Atividades complementares e AEE';
+            break;
+        default:
+            schoolYearStr = 'Não classificado';
+    }
+    return schoolYearStr;
+}
+
+function processResultSet(querySet, querySetLabels = ["result"], singleResult = false) {
+    const resultMap = new Map();
+    let resultIdx = 0;
+    // loop relies on the fact that Promise.all maintains the order of the original iterable
+    for(let result of querySet) {
+        const resultLbl = querySetLabels[resultIdx];
+        resultMap[resultLbl] = [];
+        if (singleResult) {
+            resultMap[resultLbl] = result[0];
+        } else {
+            for(let row of result) {
+                log.debug(row);
+                resultMap[resultLbl].push(row);
+            }
+        }
+        resultIdx++;
+    }
+    log.debug(resultMap);
+    return resultMap;
+}
+
+function dbExecAll(querySet = []) {
+    // Issue all queries concurrently to the database, for every query object in the iterable
+    // NOTE: Array.map() returns a copy of the original array with each object 'mapped'.
+    return querySet.map((qry) => { return sqlQuery(qry.toString()); });
+}
+
+locationApp.get('/sociodemographic', (req, res, next) => {
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+
+    const populationQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .group('ibge_populacao.ano_censo');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .from('ibge_pib')
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .group('ibge_pib.ano_censo');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .from('adh_idh')
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .group('adh_idh.ano_censo');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .group('adh_analfabetismo.ano_censo');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo', 'census_year')
+        .from('adh_gini')
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .group('adh_gini.ano_censo');
+
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels, true);
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+
+    const populationQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('SUM(populacao)', 'population')
+        .field('ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('regiao.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('ibge_pib.ano_censo')
+        .order('regiao.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('AVG(idhm)', 'idhm')
+        .field('ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_idh.ano_censo')
+        .order('regiao.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('regiao.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('AVG(gini)', 'gini')
+        .field('ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .from('estado')
+        .from('regiao')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .group('regiao.nome')
+        .group('adh_gini.ano_censo')
+        .order('regiao.nome');
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels, true);
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+    // load all cities by state and compute the sociodemographic and educational information
+    const populationQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('estado.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('ibge_pib.ano_censo')
+        .order('estado.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_idh.ano_censo')
+        .order('estado.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('estado.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .from('estado')
+        .where(`estado.pk_estado_id = ${stateId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .where('municipio.fk_estado_id = estado.pk_estado_id')
+        .group('estado.nome')
+        .group('adh_gini.ano_censo')
+        .order('estado.nome');
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels, true);
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/sociodemographic/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const populationYearQry = squel.select()
+        .field('MAX(ibge_populacao.ano_censo)')
+        .from('ibge_populacao');
+    // load all cities by state and compute the sociodemographic and educational information
+    const populationQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('SUM(populacao)', 'population')
+        .field('ibge_populacao.ano_censo', 'census_year')
+        .from('ibge_populacao')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`ibge_populacao.ano_censo IN (${populationYearQry.toString()})`)
+        .where('ibge_populacao.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('ibge_populacao.ano_censo')
+        .order('municipio.nome');
+
+    const pibYearQry = squel.select()
+        .field('MAX(ibge_pib.ano_censo)')
+        .from('ibge_pib');
+
+    const pibQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('AVG(ibge_pib.pib_per_capita)', 'gdp_per_capita')
+        .field('ibge_pib.ano_censo', 'census_year')
+        .from('ibge_pib')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`ibge_pib.ano_censo IN (${pibYearQry.toString()})`)
+        .where('ibge_pib.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('ibge_pib.ano_censo')
+        .order('municipio.nome');
+
+    const idhYearQry = squel.select()
+        .field('MAX(adh_idh.ano_censo)')
+        .from('adh_idh');
+
+    const idhQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('AVG(idhm)', 'idhm')
+        .field('adh_idh.ano_censo', 'census_year')
+        .from('adh_idh')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_idh.ano_censo IN (${idhYearQry.toString()})`)
+        .where('adh_idh.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_idh.ano_censo')
+        .order('municipio.nome');
+
+    const analfabYearQry = squel.select()
+        .field('MAX(adh_analfabetismo.ano_censo)')
+        .from('adh_analfabetismo');
+
+    const analfabQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('AVG(t_analf15m)', 'analfabetism')
+        .field('adh_analfabetismo.ano_censo', 'census_year')
+        .from('adh_analfabetismo')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_analfabetismo.ano_censo IN (${analfabYearQry.toString()})`)
+        .where('adh_analfabetismo.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_analfabetismo.ano_censo')
+        .order('municipio.nome');
+
+    const giniYearQry = squel.select()
+        .field('MAX(adh_gini.ano_censo)')
+        .from('adh_gini');
+
+    const giniQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('AVG(gini)', 'gini')
+        .field('adh_gini.ano_censo', 'census_year')
+        .from('adh_gini')
+        .from('municipio')
+        .where(`municipio.pk_cod_ibge = ${cityId}`)
+        .where(`adh_gini.ano_censo IN (${giniYearQry.toString()})`)
+        .where('adh_gini.fk_municipio_id = municipio.pk_cod_ibge')
+        .group('municipio.nome')
+        .group('adh_gini.ano_censo')
+        .order('municipio.nome');
+    // map query objects to their respective response labels
+    const queryLabels = [ "population", "gdp", "idh", "analfab", "gini" ];
+    const querySet = [ populationQry, pibQry, idhQry, analfabQry, giniQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels, true);
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational', (req, res, next) => {
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('escola.ano_censo');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('escola.tipo_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo')
+        .order('escola.tipo_localizacao');
+
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .from('turma')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .order('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('\'Brasil\'', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .order('etapa_ensino.pk_etapa_ensino_id');
+
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('estado')
+        .from('regiao')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('regiao.nome')
+        .group('escola.ano_censo')
+        .order('regiao.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('estado')
+        .from('regiao')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where('estado.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`regiao.pk_regiao_id = ${regionId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('regiao.nome')
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo')
+        .order('regiao.nome')
+        .order('escola.tipo_localizacao');
+
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .from('turma')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('regiao.nome')
+        .order('regiao.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('regiao.nome')
+        .order('regiao.nome')
+        .order('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('regiao.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('regiao')
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('regiao.nome')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .order('regiao.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id');
+
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('estado')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where(`escola.fk_estado_id = ${stateId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('estado.nome')
+        .group('escola.ano_censo')
+        .order('estado.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('estado')
+        .where('escola.fk_estado_id = estado.pk_estado_id')
+        .where(`escola.fk_estado_id = ${stateId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('estado.nome')
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo')
+        .order('estado.nome')
+        .order('escola.tipo_localizacao');
+
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .from('turma')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('estado.nome')
+        .order('estado.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('estado.nome')
+        .order('estado.nome')
+        .order('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('estado.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('estado')
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('estado.nome')
+        .order('estado.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id');
+
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const censusYearQry = squel.select()
+        .field('MAX(escola.ano_censo)', 'ano_censo')
+        .from('escola')
+        .toString();
+
+    const totalSchoolsQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('0', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('municipio')
+        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`escola.fk_municipio_id = ${cityId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('municipio.nome')
+        .group('escola.ano_censo')
+        .order('municipio.nome');
+
+    const schoolsPerLocationQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('escola.tipo_localizacao', 'location')
+        .field('COUNT(DISTINCT(escola.cod_entidade))', 'total')
+        .field('escola.ano_censo', 'census_year')
+        .from('escola')
+        .from('municipio')
+        .where('escola.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`escola.fk_municipio_id = ${cityId}`)
+        .where(`escola.ano_censo IN (${censusYearQry})`)
+        .where('escola.id_tipo_turma = 0')
+        .group('municipio.nome')
+        .group('escola.tipo_localizacao')
+        .group('escola.ano_censo')
+        .order('municipio.nome')
+        .order('escola.tipo_localizacao');
+
+    const schoolClassYearQry = squel.select()
+        .field('MAX(turma.ano_censo)')
+        .from('turma')
+        .toString();
+
+    const enrollmentsQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .from('turma')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('turma.ano_censo')
+        .group('municipio.nome')
+        .order('municipio.nome');
+
+    const enrollmentsPerAdmDepQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('dependencia_adm.nome', 'adm_dependency')
+        .from('turma')
+        .from('dependencia_adm')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('dependencia_adm.nome')
+        .group('municipio.nome')
+        .order('municipio.nome')
+        .order('dependencia_adm.nome');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('municipio.nome', 'name')
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('municipio')
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .where(`turma.ano_censo IN (${schoolClassYearQry})`)
+        .group('turma.ano_censo')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('municipio.nome')
+        .order('municipio.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id');
+
+    const queryLabels = [ "school", "school_per_location", "enrollment", "enrollment_per_adm_dep",
+        "enrollment_per_school_level" ];
+    const querySet = [ totalSchoolsQry, schoolsPerLocationQry, enrollmentsQry,
+        enrollmentsPerAdmDepQry, enrollmentsPerSchoolLevelQry];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet)).then((queryResults) => {
+        req.result = processResultSet(queryResults, queryLabels);
+        for(let label in req.result) {
+            for(let row of req.result[label]) {
+                if (row.hasOwnProperty('location')) {
+                    row.location = locationIdToStr(row.location);
+                }
+            }
+        }
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/school_level', (req, res, next) => {
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('etapa_ensino.pk_etapa_ensino_id')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/school_level/region/:id', (req, res, next) => {
+    const regionId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('regiao')
+        .where(`turma.fk_regiao_id = ${regionId}`)
+        .where('turma.fk_regiao_id = regiao.pk_regiao_id')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('regiao.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('regiao.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/school_level/state/:id', (req, res, next) => {
+    const stateId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('estado')
+        .where(`turma.fk_estado_id = ${stateId}`)
+        .where('turma.fk_estado_id = estado.pk_estado_id')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('estado.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('estado.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+locationApp.get('/educational/school_level/city/:id', (req, res, next) => {
+    const cityId = parseInt(req.params.id, 10);
+
+    const enrollmentsPerSchoolLevelYearQry = squel.select()
+        .field('MAX(turma.ano_censo)', 'census_year')
+        .from('turma');
+
+    const enrollmentsPerSchoolLevelQry = squel.select()
+        .field('COALESCE(SUM(turma.num_matriculas), 0)', 'total')
+        .field('turma.ano_censo', 'census_year')
+        .field('turma.serie_ano', 'school_year')
+        .field('etapa_ensino.desc_etapa', 'school_level')
+        .from('turma')
+        .from('etapa_ensino')
+        .from('municipio')
+        .where(`turma.fk_municipio_id = ${cityId}`)
+        .where('turma.fk_municipio_id = municipio.pk_cod_ibge')
+        .where(`turma.ano_censo IN (${enrollmentsPerSchoolLevelYearQry.toString()})`)
+        .where('turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id')
+        .where('turma.fk_tipo_turma_id <= 3')
+        .group('municipio.nome')
+        .group('etapa_ensino.desc_etapa')
+        .group('etapa_ensino.pk_etapa_ensino_id')
+        .group('turma.serie_ano')
+        .group('turma.ano_censo')
+        .order('municipio.nome')
+        .order('etapa_ensino.pk_etapa_ensino_id')
+        .order('turma.serie_ano')
+        .order('turma.ano_censo');
+
+    const queryLabels = [ 'enrollment_per_school_level', 'enrollment_census_year' ];
+    const querySet = [ enrollmentsPerSchoolLevelQry, enrollmentsPerSchoolLevelYearQry ];
+    // wait until all queries finish or one of them fail
+    Promise.all(dbExecAll(querySet, enrollmentsPerSchoolLevelYearQry)).then((queryResults) => {
+        const result = queryResults[0];
+        const censusYear = queryResults[1][0]['census_year'];
+
+        let school_levels = {};
+        for(let i = 0; i < result.length; ++i) {
+            const school_year  = schoolYearIdToStr(result[i].school_year);
+            const school_level = result[i].school_level;
+            const census_year = result[i].census_year;
+            if (typeof school_levels[school_level] === 'undefined') {
+                school_levels[school_level] = {};
+            }
+            school_levels[school_level][school_year] = parseInt(result[i].total, 10);
+        }
+
+        let response = [];
+        for(let level in school_levels) {
+            if (school_levels.hasOwnProperty(level)) {
+                let sclevel = {};
+                sclevel["degree"] = level;
+                sclevel["census_year"] = parseInt(censusYear, 10);
+                sclevel["table"] = [];
+                for(let school_year in school_levels[level]) {
+                    if (school_levels[level].hasOwnProperty(school_year)) {
+                        let enrollment = { 'title' : school_year,
+                                           'value' : school_levels[level][school_year] };
+                        sclevel["table"].push(enrollment);
+                    }
+                }
+                response.push(sclevel);
+            }
+        }
+        req.result = response;
+        next();
+    }).catch((error) => {
+        log.error(`[SQL query error] ${error}`);
+        next(error);
+    });
+}, response('location'));
+
+module.exports = locationApp;
diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js
index 4ae980e2a1715f4170c3881c76d2af49d7ecb8d3..3af30fb1b5b3b7dde4f4559f0d4abf18974a2d88 100644
--- a/src/libs/routes/school.js
+++ b/src/libs/routes/school.js
@@ -28,16 +28,21 @@ const response = require(`${libs}/middlewares/response`);
 // Get a school by it's id
 schoolApp.get('/:id', (req, res, next) => {
     req.sql.from('escola')
-        .where('escola.cod_entidade = ?', parseInt(req.params.id, 10));
+        .field('cod_entidade', 'pk_escola_id')
+        .field('cod_entidade')
+        .field('ano_censo')
+        .field('fk_municipio_id')
+        .field('fk_estado_id')
+        .where('cod_entidade = ?', parseInt(req.params.id, 10));
     next();
 }, query, response('school'));
 
 // Get all schools from a state
 schoolApp.get('/state/:id', (req, res, next) => {
     req.sql.from('escola')
-        .field('escola.cod_entidade')
+        .field('cod_entidade', 'pk_escola_id')
+        .field('cod_entidade')
         .field('ano_censo')
-        .field('fk_estado_id')
         .field('fk_municipio_id')
         .where('fk_estado_id = ?', parseInt(req.params.id, 10));
     next();
@@ -46,10 +51,10 @@ schoolApp.get('/state/:id', (req, res, next) => {
 // Get all schools from a city
 schoolApp.get('/city/:id', (req, res, next) => {
     req.sql.from('escola')
-        .field('escola.cod_entidade')
+        .field('cod_entidade', 'pk_escola_id')
+        .field('cod_entidade')
         .field('ano_censo')
         .field('fk_estado_id')
-        .field('fk_municipio_id')
         .where('fk_municipio_id = ?', parseInt(req.params.id, 10));
     next();
 }, query, response('school'));
diff --git a/src/libs/routes/simulation.js b/src/libs/routes/simulation.js
index 16c7dcf848e0851c71a5c5015d554087a6f4e1b6..6469d4d6b3df70077b9f38fca96c6ae479133022 100644
--- a/src/libs/routes/simulation.js
+++ b/src/libs/routes/simulation.js
@@ -4,7 +4,6 @@ const simulationApp = express();
 
 const libs = `${process.cwd()}/libs`;
 
-
 const log = require(`${libs}/log`)(module);
 
 const squel = require('squel');
diff --git a/src/server.js b/src/server.js
index aaf9309ef94b0e30a9683cc9fcc854e4205b8e7b..ccc5e884702641fca04e0fc0480860a4b72300ef 100644
--- a/src/server.js
+++ b/src/server.js
@@ -18,9 +18,6 @@ if (!compatVersion()) {
 // Set default port: first environment variable PORT, then configuration and last 3000
 app.set('port', process.env.PORT || config.port || 3000);
 process.env.NODE_ENV = process.env.NODE_ENV || 'development';
-
-app.set('port', process.env.PORT || config.port || 3000);
-
 // Set default ip: first environment variable IOP, then configuration and last '127.0.0.1'
 app.set('ip', process.env.IP || config.ip || '127.0.0.1');
 
diff --git a/src/test/api.js b/src/test/api.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5476ea6352d086cb8d43f8e1f091686bc4f91c4
--- /dev/null
+++ b/src/test/api.js
@@ -0,0 +1,49 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+describe('API is running', () => {
+    it('should respond it\'s running', (done) => {
+        chai.request(server)
+            .get('/api/v1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('msg');
+                done();
+            })
+    });
+
+    it('should respond with 404 error', (done) => {
+        chai.request(server)
+            .get('/api/v1/thisrouteshouldgivea404')
+            .end((err, res) => {
+                res.should.have.status(404);
+                res.should.be.json;
+                res.body.should.have.property('error');
+                done();
+            })
+    });
+});
diff --git a/src/test/city.js b/src/test/city.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb5f40992a65322dd620641166ca6285e37f6ab5
--- /dev/null
+++ b/src/test/city.js
@@ -0,0 +1,93 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+
+describe('request cities', () => {
+    it('should list all cities', (done) => {
+        chai.request(server)
+            .get('/api/v1/city')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_municipio_id');
+                res.body.result[0].should.have.property('fk_estado_id');
+                res.body.result[0].should.have.property('nome');
+                res.body.result[0].should.have.property('codigo_ibge');
+                done();
+            });
+    });
+
+    it('should list a city by id', (done) => {
+        chai.request(server)
+            .get('/api/v1/city/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_municipio_id');
+                res.body.result[0].should.have.property('fk_estado_id');
+                res.body.result[0].should.have.property('nome');
+                res.body.result[0].should.have.property('codigo_ibge');
+                done();
+            });
+    });
+
+    it('should list a city by codigo_ibge', (done) => {
+        chai.request(server)
+            .get('/api/v1/city/ibge/1200013')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_municipio_id');
+                res.body.result[0].should.have.property('fk_estado_id');
+                res.body.result[0].should.have.property('nome');
+                res.body.result[0].should.have.property('codigo_ibge');
+                done();
+            });
+    });
+
+    it('should list all cities from a state', (done) => {
+        chai.request(server)
+            .get('/api/v1/city/state/41')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_municipio_id');
+                res.body.result[0].should.have.property('fk_estado_id');
+                res.body.result[0].should.have.property('nome');
+                res.body.result[0].should.have.property('codigo_ibge');
+                done();
+            })
+    })
+});
+
diff --git a/src/test/enrollment.js b/src/test/enrollment.js
new file mode 100644
index 0000000000000000000000000000000000000000..dc7fcb2ef6cea7da1e0adfe7ca7c0abf3b523507
--- /dev/null
+++ b/src/test/enrollment.js
@@ -0,0 +1,195 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+describe('request enrollments', () => {
+    it('should list the year range', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/year_range')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('start_year');
+                res.body.result[0].should.have.property('end_year');
+                done();
+            });
+    });
+
+    it('should list the locations', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/location')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('location_id');
+                res.body.result[0].should.have.property('description');
+                done();
+            });
+    });
+
+    it('should list the education level', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/education_level')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('id');
+                res.body.result[0].should.have.property('name');
+                done();
+            });
+    });
+
+    it('should list the administrative dependencies', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment/adm_dependency ')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('id');
+                res.body.result[0].should.have.property('name');
+                done();
+            });
+    });
+
+    it('should list enrollments', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('name');
+                res.body.result[0].should.have.property('total');
+                done();
+            });
+    });
+
+    it('should list enrollments with valid filters', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?filter=min_year:2014,state:41')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('name');
+                res.body.result[0].should.have.property('total');
+                done();
+            });
+    });
+
+    it('should list enrollments with invalid filters', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?filter=foo:2010,bar:41')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('name');
+                res.body.result[0].should.have.property('total');
+                done();
+            });
+    });
+
+    it('should list enrollments with valid dimensions', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?dims=region,state,adm_dependency,location&filter=min_year:2014,region:4')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('region_name');
+                res.body.result[0].should.have.property('state_name');
+                res.body.result[0].should.have.property('adm_dependency_name');
+                res.body.result[0].should.have.property('location_name');
+                res.body.result[0].should.have.property('total');
+                done();
+            });
+    });
+
+    it('should list enrollments with invalid dimensions', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?dims=foo,bar')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('name');
+                res.body.result[0].should.have.property('total');
+                done();
+            });
+    });
+
+    it('should list enrollments with valid dimensions and filters', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?dims=region,state,education_level,school&filter=min_year:2013,max_year:2014,city:4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('region_name');
+                res.body.result[0].should.have.property('state_name');
+                //res.body.result[0].should.have.property('school_name');
+                res.body.result[0].should.have.property('education_level');
+                res.body.result[0].should.have.property('total');
+                res.body.result[0].should.have.property('year');
+                done();
+            });
+    });
+
+    it('should list enrollments using all dimensions and filters', (done) => {
+        chai.request(server)
+            .get('/api/v1/enrollment?dims=region,state,city,education_level,school,adm_dependency,location&filter=min_year:2013,max_year:2014,city:4106902,adm_dependency:3,location:1,education_level:99')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('region_name');
+                res.body.result[0].should.have.property('state_name');
+                //res.body.result[0].should.have.property('school_name');
+                res.body.result[0].should.have.property('education_level');
+                res.body.result[0].should.have.property('location_name');
+                res.body.result[0].should.have.property('adm_dependency_name');
+                res.body.result[0].should.have.property('total');
+                res.body.result[0].should.have.property('year');
+                done();
+            });
+    });
+
+
+});
diff --git a/src/test/location.js b/src/test/location.js
new file mode 100644
index 0000000000000000000000000000000000000000..42761a8dadf84c63b1c4202fe27e17b9fa2aa920
--- /dev/null
+++ b/src/test/location.js
@@ -0,0 +1,565 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+const testTimeout = 5000;
+
+describe('test location', () => {
+    it('should return the expected response format for sociodemographic data for the whole country', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for sociodemographic data for a city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/sociodemographic/city/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('population');
+                res.body.result.should.have.property('gdp');
+                res.body.result.should.have.property('idh');
+                res.body.result.should.have.property('analfab');
+                res.body.result.should.have.property('gini');
+                // test response attributes for population
+                res.body.result.population.should.have.property('name');
+                res.body.result.population.should.have.property('population');
+                res.body.result.population.should.have.property('census_year');
+                // test response attributes for gdp
+                res.body.result.gdp.should.have.property('name');
+                res.body.result.gdp.should.have.property('gdp_per_capita');
+                res.body.result.gdp.should.have.property('census_year');
+                // test response attributes for idh
+                res.body.result.idh.should.have.property('name');
+                res.body.result.idh.should.have.property('idhm');
+                res.body.result.idh.should.have.property('census_year');
+                // test response attributes for analfab
+                res.body.result.analfab.should.have.property('name');
+                res.body.result.analfab.should.have.property('analfabetism');
+                res.body.result.analfab.should.have.property('census_year');
+                // test response attributes for gini
+                res.body.result.gini.should.have.property('name');
+                res.body.result.gini.should.have.property('gini');
+                res.body.result.gini.should.have.property('census_year');
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for the whole country', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
+                // test response attributes for school
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
+                // test response attributes for school
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
+                // test response attributes for school
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the expected response format for educational data for a country city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/city/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                // test result type
+                res.body.result.should.be.a('object');
+                res.body.result.should.have.property('school');
+                res.body.result.school.should.be.a('array');
+                res.body.result.should.have.property('school_per_location');
+                res.body.result.school_per_location.should.be.a('array');
+                res.body.result.should.have.property('enrollment');
+                res.body.result.enrollment.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_adm_dep');
+                res.body.result.enrollment_per_adm_dep.should.be.a('array');
+                res.body.result.should.have.property('enrollment_per_school_level');
+                res.body.result.enrollment_per_school_level.should.be.a('array');
+                // test response attributes for school
+                res.body.result.school.should.a('array');
+                res.body.result.school.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for school_per_location
+                res.body.result.school_per_location.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('location');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment
+                res.body.result.enrollment.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                });
+                // test response attributes for enrollment_per_adm_dep
+                res.body.result.enrollment_per_adm_dep.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('adm_dependency');
+                });
+                // test response attributes for enrollment_per_school_level
+                res.body.result.enrollment_per_school_level.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('name');
+                    row.should.have.property('total');
+                    row.should.have.property('census_year');
+                    row.should.have.property('school_level');
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a region', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a state', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/state/42')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+
+    it('should return the correct format of enrollments per school level for a city', (done) => {
+        chai.request(server)
+            .get('/api/v1/location/educational/school_level/state/4106902')
+            .end((err, res) => {
+                res.should.have.status(200);
+                // test response format
+                res.should.be.json;
+                // test for result attribute in the response
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                // test response attributes for school
+                res.body.result.forEach((row) => {
+                    row.should.be.a('object');
+                    row.should.have.property('degree');
+                    row.should.have.property('census_year');
+                    row.should.have.property('table');
+                    row.table.should.be.a('array');
+                    row.table.forEach((tableRow) => {
+                        tableRow.should.be.a('object');
+                        tableRow.should.have.property('title');
+                        tableRow.should.have.property('value');
+                        tableRow.title.should.be.a('String');
+                        tableRow.value.should.be.a('Number');
+                    });
+                });
+                done();
+            });
+    }).timeout(testTimeout);
+});
diff --git a/src/test/region.js b/src/test/region.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2f67d2f879dc45eb80f878089a24e2ffed3464c
--- /dev/null
+++ b/src/test/region.js
@@ -0,0 +1,56 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+describe('request regions', () => {
+    it('should list all regions', (done) => {
+        chai.request(server)
+            .get('/api/v1/region')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_regiao_id');
+                res.body.result[0].should.have.property('nome');
+                done();
+            });
+    });
+
+    it('should list region by id', (done) => {
+        chai.request(server)
+            .get('/api/v1/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result.should.have.length(1);
+                res.body.result[0].should.have.property('pk_regiao_id');
+                res.body.result[0].should.have.property('nome');
+                done();
+            });
+    });
+});
diff --git a/src/test/response.js b/src/test/response.js
new file mode 100644
index 0000000000000000000000000000000000000000..bdafc9d89eefa01966bc4171ebcbd373924479cf
--- /dev/null
+++ b/src/test/response.js
@@ -0,0 +1,55 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+
+describe('test response', () => {
+    it('should list all regions in json', (done) => {
+        chai.request(server)
+            .get('/api/v1/region')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                done();
+            });
+    });
+    it('should list all regions in xml', (done) => {
+        chai.request(server)
+            .get('/api/v1/region?format=xml')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.xml;
+                done();
+            });
+    });
+    it('should list all regions in csv', (done) => {
+        chai.request(server)
+            .get('/api/v1/region?format=csv')
+            .end((err, res) => {
+                res.should.have.status(200);
+                done();
+            });
+    });
+});
diff --git a/src/test/school.js b/src/test/school.js
new file mode 100644
index 0000000000000000000000000000000000000000..01d44b0292ff90110f8dcc4448c2ef23030844ab
--- /dev/null
+++ b/src/test/school.js
@@ -0,0 +1,75 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+describe('request schools', () => {
+    it('should list a school by id', (done) => {
+        chai.request(server)
+            .get('/api/v1/school/11000023')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_escola_id');
+                res.body.result[0].should.have.property('ano_censo');
+                res.body.result[0].should.have.property('cod_entidade');
+                //res.body.result[0].should.have.property('nome_entidade');
+                done();
+            });
+    });
+
+    it('should list all schools from a state', (done) => {
+        chai.request(server)
+            .get('/api/v1/school/state/41')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_escola_id');
+                res.body.result[0].should.have.property('ano_censo');
+                res.body.result[0].should.have.property('cod_entidade');
+                //res.body.result[0].should.have.property('nome_entidade');
+                done();
+            });
+    });
+
+    it('should list all schools from a city', (done) => {
+        chai.request(server)
+            .get('/api/v1/school/city/4102802')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_escola_id');
+                res.body.result[0].should.have.property('ano_censo');
+                res.body.result[0].should.have.property('cod_entidade');
+                //res.body.result[0].should.have.property('nome_entidade');
+                done();
+            })
+    })
+});
diff --git a/src/test/simulation.js b/src/test/simulation.js
new file mode 100644
index 0000000000000000000000000000000000000000..c74ca3ae0c8d47171c7ab402d9e6ff460dcc46a5
--- /dev/null
+++ b/src/test/simulation.js
@@ -0,0 +1,408 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+const mongoose = require('../libs/db/mongoose');
+const Simulation = require('../libs/models/simulation');
+const User = require('../libs/models/user');
+
+chai.use(chaiHttp);
+
+describe('Requires a simulation', () => {
+    let newSimulation;
+
+    beforeEach(() => {
+        Simulation.remove({}, (err) => {
+            console.log('Test collection purged');
+        });
+    });
+
+    it('should create a new simulation', (done) => {
+        chai.request(server)
+            .post('/api/v1/simulation')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({ name: 'test_entry' })
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('id');
+                res.body.id.should.be.a('string');
+                Simulation.findById(res.body.id, (err, simulation) => {
+                    simulation.should.have.property('name');
+                    simulation.name.should.be.a('string');
+                    simulation.name.should.equal('test_entry');
+                    done();
+                });
+            });
+    });
+    it('should not create a nameless simulation', (done) => {
+        chai.request(server)
+            .post('/api/v1/simulation')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.not.have.property('id');
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                Simulation.findById(res.body.id, (err, simulation) => {
+                    expect(simulation).to.not.exist;
+                    done();
+                });
+            });
+    });
+    it('should find an existing simulation', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .get(`/api/v1/simulation/${id}`)
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('_id');
+                    res.body._id.should.be.a('string');
+                    res.body.should.have.property('name');
+                    res.body._id.should.be.a('string');
+                    done();
+                });
+        });
+    });
+    it('should not find an unexisting simulation', (done) => {
+        newSimulation = new Simulation();
+        let id = newSimulation._id;
+        chai.request(server)
+            .get(`/api/v1/simulation/${id}`)
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                done();
+            });
+    });
+    it('should update an existing simulation\'s location', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({ location: 5 })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('id');
+                    res.body.id.should.be.a('string');
+                    Simulation.findById(res.body.id, (err, simulation) => {
+                        simulation.should.have.property('name');
+                        simulation.name.should.be.a('string');
+                        simulation.name.should.equal('test');
+                        simulation.should.have.property('location');
+                        simulation.location.should.be.a('number');
+                        simulation.location.should.equal(5);
+                        done();
+                    });
+                });
+        });
+    });
+    it('should update multiple fields on a single request', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    name: 'new_name',
+                    location: 5,
+                    time: 3,
+                    failure_rate: [0.1, 0.2, 0.3],
+                    goals_care: [0.3, 0.2, 0.1],
+                    goals_inclusion: [0.8, 0.9, 1]
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('id');
+                    res.body.id.should.be.a('string');
+                    Simulation.findById(res.body.id, (err, simulation) => {
+                        simulation.should.have.property('name');
+                        simulation.name.should.be.a('string');
+                        simulation.name.should.equal('new_name');
+                        simulation.should.have.property('location');
+                        simulation.location.should.be.a('number');
+                        simulation.location.should.equal(5);
+                        simulation.should.have.property('time');
+                        simulation.time.should.be.a('number');
+                        simulation.time.should.equal(3);
+                        simulation.should.have.property('failure_rate');
+                        simulation.failure_rate.should.be.a('array');
+                        simulation.failure_rate.length.should.equal(3);
+                        simulation.should.have.property('goals_care');
+                        simulation.goals_care.should.be.a('array');
+                        simulation.goals_care.length.should.equal(3);
+                        simulation.should.have.property('goals_inclusion');
+                        simulation.goals_inclusion.should.be.a('array');
+                        simulation.goals_inclusion.length.should.equal(3);
+                        done();
+                    });
+                });
+        });
+    });
+    it('should not update an unexisting simulation', (done) => {
+        newSimulation = new Simulation();
+        let id = newSimulation._id;
+        chai.request(server)
+            .post(`/api/v1/simulation/${id}`)
+            .send({ location: 5 })
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                done();
+            });
+    });
+    it('should update an existing simulation\'s time', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({ time: 5 })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('id');
+                    res.body.id.should.be.a('string');
+                    Simulation.findById(res.body.id, (err, simulation) => {
+                        simulation.should.have.property('name');
+                        simulation.name.should.be.a('string');
+                        simulation.should.have.property('time');
+                        simulation.time.should.be.a('number');
+                        simulation.time.should.equal(5);
+                        done();
+                    });
+                });
+        });
+    });
+    it('should not change results for empty post requests', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    done();
+                });
+        });
+    });
+    it('should not update in case of invalid field', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    name: 'other_name',
+                    totally_not_valid_value_for_an_entry: 'not hacking this api',
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    Simulation.findById(id, (err, simulation) => {
+                        simulation.name.should.equal('test');
+                        done();
+                    });
+                });
+        });
+    });
+    it('should include consistent enrollment tables', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: 5,
+                    enrollments: "[[100, 150, 200, 250, 300]]",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('id');
+                    res.body.id.should.be.a('string');
+                    Simulation.findById(res.body.id, (err, simulation) => {
+                        simulation.should.have.property('name');
+                        simulation.name.should.be.a('string');
+                        simulation.should.have.property('time');
+                        simulation.time.should.be.a('number');
+                        simulation.time.should.equal(5);
+                        done();
+                    });
+                });
+        });
+    });
+    it('should not accept an invalid time', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: "I'm an inocent time entry, don't mind me",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    });
+                    done();
+                });
+    });
+    it('should not accept enrollments table different than provided time', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: 5,
+                    enrollments: "[[1,2,3]]",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    done();
+                });
+        });
+    });
+    it('should not include arrays of non arrays as enrollments', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: 5,
+                    enrollments: "[\"Tomato\"]",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    done();
+                });
+        });
+    });
+    it('should not accept non array enrollments', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: 5,
+                    enrollments: "Am I still wanted here?",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    done();
+                });
+        });
+    });
+    it('should not accept an enrollment with anything other than a number', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .post(`/api/v1/simulation/${id}`)
+                .send({
+                    time: 5,
+                    enrollments: "[[1,2,\"malicious payload\",4,5]]",
+                })
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(false);
+                    done();
+                });
+        });
+    });
+    it('should delete an entry', (done) => {
+        newSimulation = new Simulation();
+        newSimulation.name = 'test';
+        newSimulation.save((err, sim) => {
+            let id = sim._id;
+            chai.request(server)
+                .delete(`/api/v1/simulation/${id}`)
+                .end((err, res) => {
+                    res.should.have.status(200);
+                    res.should.be.json;
+                    res.body.should.have.property('success');
+                    res.body.success.should.equal(true);
+                    done();
+                });
+        });
+    });
+    it('should not delete an unexisting entry', (done) => {
+        let sim = new Simulation();
+        let id = sim._id;
+        chai.request(server)
+            .delete(`/api/v1/simulation/${id}`)
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                done();
+            });
+    });
+});
diff --git a/src/test/state.js b/src/test/state.js
new file mode 100644
index 0000000000000000000000000000000000000000..6a2230fbeaad71e7cc2a5c5071c86c6a0d61255e
--- /dev/null
+++ b/src/test/state.js
@@ -0,0 +1,75 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+chai.use(chaiHttp);
+
+
+describe('request states', () => {
+    it('should list all states', (done) => {
+        chai.request(server)
+            .get('/api/v1/state')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_estado_id');
+                res.body.result[0].should.have.property('fk_regiao_id');
+                res.body.result[0].should.have.property('nome');
+                done();
+            });
+    });
+
+    it('should list a state by id', (done) => {
+        chai.request(server)
+            .get('/api/v1/state/11')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result.should.have.length(1);
+                res.body.result[0].should.have.property('pk_estado_id');
+                res.body.result[0].should.have.property('fk_regiao_id');
+                res.body.result[0].should.have.property('nome');
+                done();
+            });
+    });
+
+    it('should list states by region id', (done) => {
+        chai.request(server)
+            .get('/api/v1/state/region/1')
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('result');
+                res.body.result.should.be.a('array');
+                res.body.result[0].should.have.property('pk_estado_id');
+                res.body.result[0].should.have.property('fk_regiao_id');
+                res.body.result[0].should.have.property('nome');
+                done();
+            });
+    });
+});
+
diff --git a/src/test/test.js b/src/test/test.js
deleted file mode 100644
index 8b55179e1556030ce9a90644bfbdac57624caef8..0000000000000000000000000000000000000000
--- a/src/test/test.js
+++ /dev/null
@@ -1,1459 +0,0 @@
-process.env.NODE_ENV = 'test';
-
-const chai = require('chai');
-
-const dirtyChai = require('dirty-chai');
-
-chai.use(dirtyChai);
-
-const chaiXml = require('chai-xml');
-
-chai.use(chaiXml);
-
-const chaiHttp = require('chai-http');
-
-const assert = chai.assert;
-
-const expect = chai.expect;
-
-const should = chai.should(); // actually call the function
-
-const libs = `${process.cwd()}/libs`;
-
-const server = require(`${libs}/app`);
-
-const mongoose = require('../libs/db/mongoose');
-const Simulation = require('../libs/models/simulation');
-const User = require('../libs/models/user');
-
-chai.use(chaiHttp);
-
-describe('API is running', () => {
-    it('should respond it\'s running', (done) => {
-        chai.request(server)
-            .get('/api/v1')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('msg');
-                done();
-            })
-    });
-});
-
-describe('request enrollments', () => {
-    it('should list the year range', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/year_range')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('start_year');
-                res.body.result[0].should.have.property('end_year');
-                done();
-            });
-    });
-
-    it('should list the education level', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/education_level')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('id');
-                res.body.result[0].should.have.property('name');
-                done();
-            });
-    });
-
-    it('should list the administrative dependencies', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment/adm_dependency ')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('id');
-                res.body.result[0].should.have.property('name');
-                done();
-            });
-    });
-
-    it('should list enrollments', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?filter=min_year:2010,state:41')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with invalid filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?filter=foo:2010,bar:41')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid dimensions', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,adm_dependency,location&filter=min_year:2014,region:4')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('adm_dependency_name');
-                res.body.result[0].should.have.property('location_name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with invalid dimensions', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=foo,bar')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('name');
-                res.body.result[0].should.have.property('total');
-                done();
-            });
-    });
-
-    it('should list enrollments with valid dimensions and filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,education_level,school&filter=min_year:2013,max_year:2014,city:4106902')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('school_name');
-                res.body.result[0].should.have.property('education_level');
-                res.body.result[0].should.have.property('total');
-                res.body.result[0].should.have.property('year');
-                done();
-            });
-    });
-
-    it('should list enrollments using all dimensions and filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,city,education_level,school,adm_dependency,location&filter=min_year:2013,max_year:2014,city:4106902,adm_dependency:3,location:1,education_level:99')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('region_name');
-                res.body.result[0].should.have.property('state_name');
-                res.body.result[0].should.have.property('school_name');
-                res.body.result[0].should.have.property('education_level');
-                res.body.result[0].should.have.property('location_name');
-                res.body.result[0].should.have.property('adm_dependency_name');
-                res.body.result[0].should.have.property('total');
-                res.body.result[0].should.have.property('year');
-                done();
-            });
-    });
-
-
-});
-
-describe('request regions', () => {
-    it('should list all regions', (done) => {
-        chai.request(server)
-            .get('/api/v1/region')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list region by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/region/1')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result.should.have.length(1);
-                res.body.result[0].should.have.property('pk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-});
-
-describe('request states', () => {
-    it('should list all states', (done) => {
-        chai.request(server)
-            .get('/api/v1/state')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list a state by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/state/11')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result.should.have.length(1);
-                res.body.result[0].should.have.property('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list states by region id', (done) => {
-        chai.request(server)
-            .get('/api/v1/state/region/1')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_estado_id');
-                res.body.result[0].should.have.property('fk_regiao_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-});
-
-describe('request cities', () => {
-    it('should list all cities', (done) => {
-        chai.request(server)
-            .get('/api/v1/city')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_cod_ibge');
-                res.body.result[0].should.have.property('nome');
-                res.body.result[0].should.have.property('fk_estado_id');
-                done();
-            });
-    });
-
-    it('should list a city by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/4106902')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list a city by codigo_ibge', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/ibge/4106902')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            });
-    });
-
-    it('should list all cities from a state', (done) => {
-        chai.request(server)
-            .get('/api/v1/city/state/41')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('pk_cod_ibge');
-                res.body.result[0].should.have.property('fk_estado_id');
-                res.body.result[0].should.have.property('nome');
-                done();
-            })
-    })
-});
-
-describe('request schools', () => {
-    it('should list a school by id', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/41000021')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('ano_censo');
-                res.body.result[0].should.have.property('cod_entidade');
-                done();
-            });
-    });
-
-    it('should list all schools from a state', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/state/41')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('cod_entidade');
-                res.body.result[0].should.have.property('ano_censo');
-                done();
-            });
-    });
-
-    it('should list all schools from a city', (done) => {
-        chai.request(server)
-            .get('/api/v1/school/city/4106902')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('result');
-                res.body.result.should.be.a('array');
-                res.body.result[0].should.have.property('cod_entidade');
-                res.body.result[0].should.have.property('ano_censo');
-                done();
-            })
-    })
-});
-
-describe('test response', () => {
-    it('should list all regions in json', (done) => {
-        chai.request(server)
-            .get('/api/v1/region')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                done();
-            });
-    });
-
-    it('should list all regions in xml', (done) => {
-        chai.request(server)
-            .get('/api/v1/region?format=xml')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.xml;
-                done();
-            });
-    });
-
-    it('should list all regions in csv', (done) => {
-        chai.request(server)
-            .get('/api/v1/region?format=csv')
-            .end((err, res) => {
-                res.should.have.status(200);
-                done();
-            });
-    });
-});
-
-describe('Requires a simulation', () => {
-    let newSimulation;
-
-    beforeEach(() => {
-        Simulation.remove({}, (err) => {
-            console.log('Test collection purged');
-        });
-    });
-
-    it('should create a new simulation', (done) => {
-        chai.request(server)
-            .post('/api/v1/simulation')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({ name: 'test_entry' })
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('id');
-                res.body.id.should.be.a('string');
-                Simulation.findById(res.body.id, (err, simulation) => {
-                    simulation.should.have.property('name');
-                    simulation.name.should.be.a('string');
-                    simulation.name.should.equal('test_entry');
-                    done();
-                });
-            });
-    });
-    it('should not create a nameless simulation', (done) => {
-        chai.request(server)
-            .post('/api/v1/simulation')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.not.have.property('id');
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                Simulation.findById(res.body.id, (err, simulation) => {
-                    expect(simulation).to.not.exist;
-                    done();
-                });
-            });
-    });
-    it('should find an existing simulation', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .get(`/api/v1/simulation/${id}`)
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('_id');
-                    res.body._id.should.be.a('string');
-                    res.body.should.have.property('name');
-                    res.body._id.should.be.a('string');
-                    done();
-                });
-        });
-    });
-    it('should not find an unexisting simulation', (done) => {
-        newSimulation = new Simulation();
-        let id = newSimulation._id;
-        chai.request(server)
-            .get(`/api/v1/simulation/${id}`)
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                done();
-            });
-    });
-    it('should update an existing simulation\'s location', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({ location: 5 })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('id');
-                    res.body.id.should.be.a('string');
-                    Simulation.findById(res.body.id, (err, simulation) => {
-                        simulation.should.have.property('name');
-                        simulation.name.should.be.a('string');
-                        simulation.name.should.equal('test');
-                        simulation.should.have.property('location');
-                        simulation.location.should.be.a('number');
-                        simulation.location.should.equal(5);
-                        done();
-                    });
-                });
-        });
-    });
-    it('should update multiple fields on a single request', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    name: 'new_name',
-                    location: 5,
-                    time: 3,
-                    failure_rate: [0.1, 0.2, 0.3],
-                    goals_care: [0.3, 0.2, 0.1],
-                    goals_inclusion: [0.8, 0.9, 1]
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('id');
-                    res.body.id.should.be.a('string');
-                    Simulation.findById(res.body.id, (err, simulation) => {
-                        simulation.should.have.property('name');
-                        simulation.name.should.be.a('string');
-                        simulation.name.should.equal('new_name');
-                        simulation.should.have.property('location');
-                        simulation.location.should.be.a('number');
-                        simulation.location.should.equal(5);
-                        simulation.should.have.property('time');
-                        simulation.time.should.be.a('number');
-                        simulation.time.should.equal(3);
-                        simulation.should.have.property('failure_rate');
-                        simulation.failure_rate.should.be.a('array');
-                        simulation.failure_rate.length.should.equal(3);
-                        simulation.should.have.property('goals_care');
-                        simulation.goals_care.should.be.a('array');
-                        simulation.goals_care.length.should.equal(3);
-                        simulation.should.have.property('goals_inclusion');
-                        simulation.goals_inclusion.should.be.a('array');
-                        simulation.goals_inclusion.length.should.equal(3);
-                        done();
-                    });
-                });
-        });
-    });
-    it('should not update an unexisting simulation', (done) => {
-        newSimulation = new Simulation();
-        let id = newSimulation._id;
-        chai.request(server)
-            .post(`/api/v1/simulation/${id}`)
-            .send({ location: 5 })
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                done();
-            });
-    });
-    it('should update an existing simulation\'s time', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({ time: 5 })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('id');
-                    res.body.id.should.be.a('string');
-                    Simulation.findById(res.body.id, (err, simulation) => {
-                        simulation.should.have.property('name');
-                        simulation.name.should.be.a('string');
-                        simulation.should.have.property('time');
-                        simulation.time.should.be.a('number');
-                        simulation.time.should.equal(5);
-                        done();
-                    });
-                });
-        });
-    });
-    it('should not change results for empty post requests', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    done();
-                });
-        });
-    });
-    it('should not update in case of invalid field', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    name: 'other_name',
-                    totally_not_valid_value_for_an_entry: 'not hacking this api',
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    Simulation.findById(id, (err, simulation) => {
-                        simulation.name.should.equal('test');
-                        done();
-                    });
-                });
-        });
-    });
-    it('should include consistent enrollment tables', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: 5,
-                    enrollments: "[[100, 150, 200, 250, 300]]",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('id');
-                    res.body.id.should.be.a('string');
-                    Simulation.findById(res.body.id, (err, simulation) => {
-                        simulation.should.have.property('name');
-                        simulation.name.should.be.a('string');
-                        simulation.should.have.property('time');
-                        simulation.time.should.be.a('number');
-                        simulation.time.should.equal(5);
-                        done();
-                    });
-                });
-        });
-    });
-    it('should not accept an invalid time', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: "I'm an inocent time entry, don't mind me",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    });
-                    done();
-                });
-    });
-    it('should not accept enrollments table different than provided time', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: 5,
-                    enrollments: "[[1,2,3]]",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    done();
-                });
-        });
-    });
-    it('should not include arrays of non arrays as enrollments', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: 5,
-                    enrollments: "[\"Tomato\"]",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    done();
-                });
-        });
-    });
-    it('should not accept non array enrollments', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: 5,
-                    enrollments: "Am I still wanted here?",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    done();
-                });
-        });
-    });
-    it('should not accept an enrollment with anything other than a number', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .post(`/api/v1/simulation/${id}`)
-                .send({
-                    time: 5,
-                    enrollments: "[[1,2,\"malicious payload\",4,5]]",
-                })
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    done();
-                });
-        });
-    });
-    it('should delete an entry', (done) => {
-        newSimulation = new Simulation();
-        newSimulation.name = 'test';
-        newSimulation.save((err, sim) => {
-            let id = sim._id;
-            chai.request(server)
-                .delete(`/api/v1/simulation/${id}`)
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(true);
-                    done();
-                });
-        });
-    });
-    it('should not delete an unexisting entry', (done) => {
-        let sim = new Simulation();
-        let id = sim._id;
-        chai.request(server)
-            .delete(`/api/v1/simulation/${id}`)
-            .end((err, res) => {
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                done();
-            });
-    });
-});
-
-describe('Saves a user', () => {
-
-    beforeEach(() => {
-        User.remove({}, (err) => {
-            if(err) {
-                console.log('Error while purging: ' + err);
-            }
-            console.log('Test collection purged');
-        });
-    });
-
-    it('should create a new user', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(true);
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                    if (err){
-                        console.log('MongoDB error: ' + err);
-                    }
-
-                    user.should.have.property('email');
-                    done();
-                });
-            });
-    });
-
-    it('should not create a user with an email that is already in use', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: '123mudar',
-                       name: 'Tequila Baby',
-                       cpf: '48303270737',
-                       schooling: 'Doutorado',
-                       course: 'Ciência da Computação',
-                       segment: 'Comunidade acadêmica',
-                       role: 'Pesquisador',
-                       institution_name: 'UFPR',
-                       state: 'PR',
-                       city: 'Cutiriba'})
-                .end((err, res) =>{
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O email informado já está cadastrado.');
-                    User.findOne({'cpf': '48303270737'}, (err, user) => {
-                            expect(user).to.not.exist;
-                            done();
-                    });
-                });
-        });
-    });
-
-    it('should not create a user with a CPF that is already in use', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'dolor@ipsum.com',
-                       password: '123mudar',
-                       name: 'Tequila Baby',
-                       cpf: '08236017907',
-                       schooling: 'Doutorado',
-                       course: 'Ciência da Computação',
-                       segment: 'Comunidade acadêmica',
-                       role: 'Pesquisador',
-                       institution_name: 'UFPR',
-                       state: 'PR',
-                       city: 'Cutiriba'})
-                .end((err, res) =>{
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O CPF informado já está cadastrado.');
-                    User.findOne({'email': 'dolor@ipsum.com'}, (err, user) => {
-                            expect(user).to.not.exist;
-                            done();
-                    });
-                });
-        });
-    });
-
-    it('should not save an user without email', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Email é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without password', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Senha é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user with invalid email', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'notavalidemail',
-                   password: '123mudar',
-                   name: 'Tequila Baby',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O email informado é inválido.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without name', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   cpf: '48303270737',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Nome é obrigatório.');
-                User.findOne({'cpf': '48303270737'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without CPF', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo CPF é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without segment', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Segmento é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without schooling', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Escolaridade é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without role', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Função é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without institution', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   role: 'Pesquisador',
-                   state: 'PR',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Instituição em que trabalha é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without city', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   role: 'Pesquisador',
-                   state: 'PR'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Cidade é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-    it('should not save an user without state', (done) => {
-        chai.request(server)
-            .post('/api/v1/user')
-            .set('content-type', 'application/x-www-form-urlencoded')
-            .set('x-apicache-bypass', 'true')
-            .send({email: 'lorem@ipsum.com',
-                   password: '123mudar',
-                   name: 'Tequila baby',
-                   schooling: 'Doutorado',
-                   cpf: '48303270737',
-                   course: 'Ciência da Computação',
-                   segment: 'Comunidade acadêmica',
-                   institution_name: 'UFPR',
-                   role: 'Pesquisador',
-                   city: 'Cutiriba'})
-            .end((err, res) =>{
-                res.should.have.status(200);
-                res.should.be.json;
-                res.body.should.have.property('success');
-                res.body.success.should.equal(false);
-                res.body.should.have.property('msg');
-                res.body.msg.should.equal('O campo Estado é obrigatório.');
-                User.findOne({'email': 'lorem@ipsum.com'}, (err, user) => {
-                        expect(user).to.not.exist;
-                        done();
-                });
-            });
-    });
-
-});
-
-describe('Authenticates a user', () => {
-
-    beforeEach(() => {
-        User.remove({}, (err) => {
-            console.log('Test collection purged');
-        });
-    });
-
-    it('should authenticate a user', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: '123mudar'})
-                .end((err, res) => {
-                    let token;
-
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(true);
-                    res.body.should.have.property('token');
-                    token = res.body.token;
-                    token.substr(0, 3).should.equal('JWT');
-                    done();
-                });
-            });
-    });
-
-    it('should not authenticate a user with wrong password', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'lorem@ipsum.com',
-                       password: 'umasenhaerrada'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('A Senha informada é inválida.')
-                    done();
-                });
-            });
-    });
-
-    it('should not authenticate a user with wrong email', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email: 'dolor@ipsum.com',
-                       password: '123mudar'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O Email informado não está cadastrado.')
-                    done();
-                });
-            });
-    });
-
-    it('should not authenticate a user with missing email', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({password: '123mudar'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O campo Email é obrigatório.')
-                    done();
-                });
-            });
-    });
-
-    it('should not authenticate a user with missing password', (done) => {
-        let newUser = new User();
-
-        newUser.email = 'lorem@ipsum.com';
-        newUser.password = '123mudar';
-        newUser.name = 'Gute';
-        newUser.cpf = '08236017907';
-        newUser.schooling = 'Doutorado';
-        newUser.course = 'Ciência da Computação';
-        newUser.segment = 'Comunidade acadêmica';
-        newUser.role = 'Pesquisador';
-        newUser.institution_name = 'UFPR';
-        newUser.state = 'PR';
-        newUser.city = 'Curitiba';
-
-        newUser.save((err) => {
-            if (err) {
-                console.log('MongoDB error:' + err);
-            }
-        }).then(function(newuser){
-            chai.request(server)
-                .post('/api/v1/user/authenticate')
-                .set('content-type', 'application/x-www-form-urlencoded')
-                .set('x-apicache-bypass', 'true')
-                .send({email:'lorem@ipsum.com'})
-                .end((err, res) => {
-                    res.should.have.status(200);
-                    res.should.be.json;
-                    res.body.should.have.property('success');
-                    res.body.success.should.equal(false);
-                    res.body.should.have.property('msg');
-                    res.body.msg.should.equal('O campo Senha é obrigatório.')
-                    done();
-                });
-            });
-    });
-});
diff --git a/src/test/user.js b/src/test/user.js
new file mode 100644
index 0000000000000000000000000000000000000000..04ab8e9e58a521ff2b555c891fa53a919066c2d9
--- /dev/null
+++ b/src/test/user.js
@@ -0,0 +1,626 @@
+process.env.NODE_ENV = 'test';
+
+const chai = require('chai');
+
+const dirtyChai = require('dirty-chai');
+
+chai.use(dirtyChai);
+
+const chaiXml = require('chai-xml');
+
+chai.use(chaiXml);
+
+const chaiHttp = require('chai-http');
+
+const assert = chai.assert;
+
+const expect = chai.expect;
+
+const should = chai.should(); // actually call the function
+
+const libs = `${process.cwd()}/libs`;
+
+const server = require(`${libs}/app`);
+
+const mongoose = require('../libs/db/mongoose');
+//const Simulation = require('../libs/models/simulation');
+const User = require('../libs/models/user');
+
+chai.use(chaiHttp);
+
+describe('Saves a user', () => {
+    beforeEach(() => {
+        User.remove({}, (err) => {
+            console.log('Test collection purged')
+        });
+    });
+
+    it('should save a user', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(true);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('Usuário cadastrado com sucesso!');
+            done();
+        });
+    });
+
+    it('should not save a user without email', (done) => {
+        let newUser = {};
+        newUser.email = null;
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Email é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without password', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Senha é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user with invalid email', (done) => {
+        let newUser = {};
+        newUser.email = 'invalid email';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O email informado é inválido.');
+            done();
+        });
+    });
+
+    it('should not save a user without a name', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Nome é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without CPF', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo CPF é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without schooling', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Escolaridade é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without segment', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Segmento é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without role', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Função é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without institution_name', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Instituição em que trabalha é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without state', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.city = 'Curitiba';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Estado é obrigatório.');
+            done();
+        });
+    });
+
+    it('should not save a user without city', (done) => {
+        let newUser = {};
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'Paraná';
+
+        chai.request(server)
+        .post('/api/v1/user/')
+        .set('content-type', 'application/x-www-form-urlencoded')
+        .set('x-apicache-bypass', 'true')
+        .send(newUser)
+        .end((err, res) => {
+            res.should.have.status(200);
+            res.should.be.json;
+            res.body.should.have.property('success');
+            res.body.success.should.equal(false);
+            res.body.should.have.property('msg');
+            res.body.msg.should.be.equal('O campo Cidade é obrigatório.');
+            done();
+        });
+    });
+
+})
+
+describe('Authenticates a user', () => {
+
+    beforeEach(() => {
+        User.remove({}, (err) => {
+            console.log('Test collection purged');
+        });
+    });
+
+    it('should authenticate a user', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'lorem@ipsum.com',
+            password: '123mudar'})
+            .end((err, res) => {
+                let token;
+
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(true);
+                res.body.should.have.property('token');
+                token = res.body.token;
+                token.substr(0, 3).should.equal('JWT');
+                done();
+            });
+        });
+    });
+
+    it('should not authenticate a user with wrong password', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'lorem@ipsum.com',
+            password: 'umasenhaerrada'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('A Senha informada é inválida.')
+                done();
+            });
+        });
+    });
+
+    it('should not authenticate a user with wrong email', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email: 'dolor@ipsum.com',
+            password: '123mudar'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O Email informado não está cadastrado.')
+                done();
+            });
+        });
+    });
+
+    it('should not authenticate a user with missing email', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({password: '123mudar'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O campo Email é obrigatório.')
+                done();
+            });
+        });
+    });
+
+    it('should not authenticate a user with missing password', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email:'lorem@ipsum.com'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('O campo Senha é obrigatório.')
+                done();
+            });
+        });
+    });
+
+    it('should not authenticate a user with wrong password', (done) => {
+        let newUser = new User();
+
+        newUser.email = 'lorem@ipsum.com';
+        newUser.password = '123mudar';
+        newUser.name = 'Gute';
+        newUser.cpf = '08236017907';
+        newUser.schooling = 'Doutorado';
+        newUser.course = 'Ciência da Computação';
+        newUser.segment = 'Comunidade acadêmica';
+        newUser.role = 'Pesquisador';
+        newUser.institution_name = 'UFPR';
+        newUser.state = 'PR';
+        newUser.city = 'Curitiba';
+
+        newUser.save((err) => {
+            if (err) {
+                console.log('MongoDB error:' + err);
+            }
+        }).then(function(newuser){
+            chai.request(server)
+            .post('/api/v1/user/authenticate')
+            .set('content-type', 'application/x-www-form-urlencoded')
+            .set('x-apicache-bypass', 'true')
+            .send({email:'lorem@ipsum.com', password: '123'})
+            .end((err, res) => {
+                res.should.have.status(200);
+                res.should.be.json;
+                res.body.should.have.property('success');
+                res.body.success.should.equal(false);
+                res.body.should.have.property('msg');
+                res.body.msg.should.equal('A Senha informada é inválida.')
+                done();
+            });
+        });
+    });
+});