diff --git a/1 b/1 new file mode 100644 index 000000000..7541d7992 --- /dev/null +++ b/1 @@ -0,0 +1,3 @@ +Error: No such container: authelia-test +Error: No such container: 2 +Error: No such container: dev/null diff --git a/package-lock.json b/package-lock.json index ebcec8a1d..1c00dd3c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -231,6 +231,25 @@ "integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A==", "dev": true }, + "@types/chokidar": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-1.7.5.tgz", + "integrity": "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ==", + "dev": true, + "requires": { + "@types/events": "1.2.0", + "@types/node": "10.0.3" + } + }, + "@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "dev": true, + "requires": { + "commander": "2.19.0" + } + }, "@types/connect": { "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", @@ -2586,23 +2605,21 @@ "dev": true, "optional": true, "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.6" } }, "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -2615,20 +2632,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2669,7 +2683,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "fs.realpath": { @@ -2684,14 +2698,14 @@ "dev": true, "optional": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" } }, "glob": { @@ -2700,12 +2714,12 @@ "dev": true, "optional": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "has-unicode": { @@ -2720,7 +2734,7 @@ "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": "2.1.2" } }, "ignore-walk": { @@ -2729,7 +2743,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "3.0.4" } }, "inflight": { @@ -2738,15 +2752,14 @@ "dev": true, "optional": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2758,9 +2771,8 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "isarray": { @@ -2773,25 +2785,22 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "minizlib": { @@ -2800,14 +2809,13 @@ "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "mkdirp": { "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2824,9 +2832,9 @@ "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" } }, "node-pre-gyp": { @@ -2835,16 +2843,16 @@ "dev": true, "optional": true, "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "needle": "2.2.0", + "nopt": "4.0.1", + "npm-packlist": "1.1.10", + "npmlog": "4.1.2", + "rc": "1.2.7", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "4.4.1" } }, "nopt": { @@ -2853,8 +2861,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1.1.1", + "osenv": "0.1.5" } }, "npm-bundled": { @@ -2869,8 +2877,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.3" } }, "npmlog": { @@ -2879,17 +2887,16 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2901,9 +2908,8 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "os-homedir": { @@ -2924,8 +2930,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "path-is-absolute": { @@ -2946,10 +2952,10 @@ "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" }, "dependencies": { "minimist": { @@ -2966,13 +2972,13 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "rimraf": { @@ -2981,7 +2987,7 @@ "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "safe-buffer": { @@ -3023,11 +3029,10 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -3036,7 +3041,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { @@ -3044,7 +3049,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-json-comments": { @@ -3059,13 +3064,13 @@ "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.2.4", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "util-deprecate": { @@ -3080,7 +3085,7 @@ "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "1.0.2" } }, "wrappy": { diff --git a/package.json b/package.json index 7ca45efc5..d7f74a9a6 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,13 @@ "node": ">=8.0.0 <10.0.0" }, "scripts": { - "start": "./scripts/authelia-scripts start", + "start": "ts-node -P ./test/tsconfig.json ./scripts/authelia-scripts start", "build": "./scripts/authelia-scripts build", "unittest": "./scripts/authelia-scripts unittest", "test": "./scripts/authelia-scripts test", "travis": "./scripts/authelia-scripts travis", - "cover": "NODE_ENV=test nyc npm t" + "cover": "NODE_ENV=test nyc npm t", + "scripts": "./scripts/authelia-scripts" }, "repository": { "type": "git", @@ -60,6 +61,8 @@ "devDependencies": { "@types/bluebird": "^3.5.4", "@types/body-parser": "^1.16.3", + "@types/chokidar": "^1.7.5", + "@types/commander": "^2.12.2", "@types/connect-redis": "0.0.7", "@types/ejs": "^2.3.33", "@types/express": "^4.0.35", diff --git a/scripts/authelia-scripts b/scripts/authelia-scripts index a5222c7c9..3f81c58ab 100755 --- a/scripts/authelia-scripts +++ b/scripts/authelia-scripts @@ -1,20 +1,17 @@ #!/usr/bin/env node var program = require('commander'); - + program .version('0.0.1') - .command('start', 'Start development environment.') + .command('suites', 'Run Authelia in specific environments.') + .command('serve', 'Run Authelia with a customized configuration.') .command('build', 'Build production version of Authelia from source.') .command('clean', 'Clean the production version of Authelia.') - .command('serve', 'Serve production version of Authelia.') - .command('test', 'Run Authelia integration tests.') .command('unittest', 'Run Authelia integration tests.') .command('travis', 'Build and test Authelia on Travis.') .command('hash-password ', 'Hash a password with SSHA512.') .command('docker', 'Docker related commands.') - .parse(process.argv); - - + .parse(process.argv); \ No newline at end of file diff --git a/scripts/authelia-scripts-docker-build b/scripts/authelia-scripts-docker-build index 0845eb856..a221c6863 100755 --- a/scripts/authelia-scripts-docker-build +++ b/scripts/authelia-scripts-docker-build @@ -3,8 +3,4 @@ var { exec } = require('./utils/exec'); var { IMAGE_NAME } = require('./utils/docker'); -async function main() { - await exec(`docker build -t ${IMAGE_NAME} .`); -} - -main(); \ No newline at end of file +exec(`docker build -t ${IMAGE_NAME} .`); \ No newline at end of file diff --git a/scripts/authelia-scripts-serve b/scripts/authelia-scripts-serve index dbfaf18f7..13c290ea3 100755 --- a/scripts/authelia-scripts-serve +++ b/scripts/authelia-scripts-serve @@ -1,49 +1,27 @@ #!/usr/bin/env node var program = require('commander'); -var execSync = require('child_process').execSync; var spawn = require('child_process').spawn; var fs = require('fs'); - + +let config; + program - .option('-c, --config ', 'Configuration file to run Authelia with.') - .option('--no-watch', 'Disable hot reload.') + .description('Run Authelia server with a custom configuration file. This is an alternative to suites in the case the environment is already set up.') + .arguments('[config_file]', 'Configuration file to run Authelia with.') + .action((configArg) => config = configArg) .parse(process.argv); -let config = 'config.yml'; // set default config file. -if (program.config) { - config = program.config; +if (!config) { + config = 'config.yml'; // set default config file.; } -// Render the production version of the nginx portal configuration -execSync('./example/compose/nginx/portal/render.js --production'); - -// Prepare the environment -execSync('./scripts/utils/prepare-environment.sh'); - -var server; -if (program.watch) { - server = spawn('./node_modules/.bin/nodemon', - ['-e', 'yml', '--ignore', './users_database*.yml', '--exec', `node dist/server/src/index.js ${config}`]); -} -else { - server = spawn('/usr/bin/env', ['node', 'dist/server/src/index.js', config]); -} - -var logStream = fs.createWriteStream('/tmp/authelia-server.log', {flags: 'a'}); - -server.stdout.on('data', (data) => { - process.stdout.write(`${data}`); -}); -server.stdout.pipe(logStream); - -server.stderr.on('data', (data) => { - process.stderr.write(`${data}`); -}); -server.stderr.pipe(logStream); +const server = spawn('/usr/bin/env', ['node', 'dist/server/src/index.js', config]); +server.stdout.pipe(process.stdout); +server.stderr.pipe(process.stderr); server.on('exit', function(statusCode) { process.exit(statusCode); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/scripts/authelia-scripts-start b/scripts/authelia-scripts-start deleted file mode 100755 index a32c4850a..000000000 --- a/scripts/authelia-scripts-start +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env node - -var program = require('commander'); -var spawn = require('child_process').spawn; -var chokidar = require('chokidar'); -var fs = require('fs'); -var kill = require('tree-kill'); - -program - .option('-s, --suite ', 'The suite to run Authelia for. This suite represents a configuration for Authelia and a set of tests for that configuration.') - .parse(process.argv) - -if (!program.suite) { - throw new Error('Please provide a suite.'); -} - -const ENVIRONMENT_FILENAME = '.suite'; -const AUTHELIA_INTERRUPT_FILENAME = '.authelia-interrupt'; -const CONFIG_FILEPATH = `test/suites/${program.suite}/config.yml`; - - -var tsWatcher = chokidar.watch(['server', 'shared/**/*.ts', 'node_modules', AUTHELIA_INTERRUPT_FILENAME, CONFIG_FILEPATH], { - persistent: true, - ignoreInitial: true, -}); - -// Properly cleanup server and client if ctrl-c is hit -process.on('SIGINT', function() { - killServer(); - killClient(); - fs.unlinkSync(ENVIRONMENT_FILENAME); - process.exit(); -}); - - -let serverProcess; -function reloadServer() { - killServer(() => { - startServer(); - }); -} - -function startServer() { - if (fs.existsSync(AUTHELIA_INTERRUPT_FILENAME)) { - console.log('Authelia is interrupted. Consider removing ' + AUTHELIA_INTERRUPT_FILENAME + ' if it\'s not expected.'); - return; - } - exec('./node_modules/.bin/tslint', ['-c', 'server/tslint.json', '-p', 'server/tsconfig.json']) - .then(function() { - serverProcess = spawn('./scripts/run-dev-server.sh', [CONFIG_FILEPATH]); - serverProcess.stdout.pipe(process.stdout); - serverProcess.stderr.pipe(process.stderr); - }); -} - -let clientProcess; -function startClient() { - clientProcess = spawn('npm', ['run', 'start'], { - cwd: './client', - env: { - ...process.env, - 'BROWSER': 'none' - } - }); - clientProcess.stdout.pipe(process.stdout); - clientProcess.stderr.pipe(process.stderr); -} - -function killServer(onExit) { - if (serverProcess) { - serverProcess.on('exit', () => { - serverProcess = undefined; - if (onExit) onExit(); - }); - try { - kill(serverProcess.pid, 'SIGKILL'); - } catch (e) { - console.error(e); - if (onExit) onExit(); - } - } else { - if (onExit) onExit(); - } -} - -function killClient(onExit) { - if (clientProcess) { - clientProcess.on('exit', () => { - clientProcess = undefined; - if (onExit) onExit(); - }); - try { - kill(clientProcess.pid, 'SIGKILL'); - } catch (e) { - console.error(e); - if (onExit) onExit(); - } - } else { - if (onExit) onExit(); - } -} - -function generateConfigurationSchema() { - return ixec('./node_modules/.bin/typescript-json-schema', - ['-o', 'server/src/lib/configuration/Configuration.schema.json', '--strictNullChecks', '--required', 'server/tsconfig.json', 'Configuration']); -} - -function reload(path) { - console.log(`File ${path} has been changed, reloading...`); - if (path.startsWith('server/src/lib/configuration/schema')) { - console.log('Schema needs to be regenerated.'); - generateConfigurationSchema(); - } - else if (path === AUTHELIA_INTERRUPT_FILENAME) { - if (fs.existsSync(path)) { - console.log('Authelia is being interrupted.'); - killServer(); - } else { - console.log('Authelia is restarting.'); - startServer(); - } - return; - } - reloadServer(); -} - -function exec(command, args) { - return new Promise((resolve, reject) => { - const cmd = spawn(command, args); - - cmd.stdout.pipe(process.stdout); - cmd.stderr.pipe(process.stderr); - cmd.on('close', (code) => { - if (code == 0) { - resolve(); - return; - } - reject(new Error('Status code ' + code)); - }); - }); -} - -async function main() { - console.log(`Create suite file ${ENVIRONMENT_FILENAME}.`); - fs.writeFileSync(ENVIRONMENT_FILENAME, program.suite); - - console.log(`Render nginx configuration...`); - await exec('./example/compose/nginx/portal/render.js'); - - console.log(`Prepare environment with docker-compose...`); - await exec('./scripts/utils/prepare-environment.sh'); - - console.log('Start watching...'); - tsWatcher.on('add', reload); - tsWatcher.on('unlink', reload); - tsWatcher.on('change', reload); - - startServer(); - startClient(); -} - -main() diff --git a/scripts/authelia-scripts-suites b/scripts/authelia-scripts-suites new file mode 100755 index 000000000..7d1c333fc --- /dev/null +++ b/scripts/authelia-scripts-suites @@ -0,0 +1,10 @@ +#!/usr/bin/env node + +var program = require('commander'); + +program + .command('start', 'Start a suite.') + .command('list', 'List the available suites') + .command('test', 'Test a suite.') + .command('clean', 'Clean remaining environment artifacts (like docker-compose env).') + .parse(process.argv); diff --git a/scripts/authelia-scripts-suites-clean b/scripts/authelia-scripts-suites-clean new file mode 100755 index 000000000..d6775472b --- /dev/null +++ b/scripts/authelia-scripts-suites-clean @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +var program = require('commander'); +var spawn = require('child_process').spawn; + +program + .description(`Clean environment artifacts from previous suites.`) + .parse(process.argv) + +runEnvProcess = spawn('./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/clean-environment.ts', { + shell: true +}); +runEnvProcess.stdout.pipe(process.stdout); +runEnvProcess.stderr.pipe(process.stderr); + +runEnvProcess.on('exit', function(statusCode) { + process.exit(statusCode); +}); \ No newline at end of file diff --git a/scripts/authelia-scripts-suites-list b/scripts/authelia-scripts-suites-list new file mode 100755 index 000000000..4891f6382 --- /dev/null +++ b/scripts/authelia-scripts-suites-list @@ -0,0 +1,10 @@ +#!/usr/bin/env node + +var program = require('commander'); +var ListSuites = require('./utils/ListSuites'); + +program + .description(`List the available suites.`) + .parse(process.argv) + +console.log(ListSuites().join("\n")); \ No newline at end of file diff --git a/scripts/authelia-scripts-suites-start b/scripts/authelia-scripts-suites-start new file mode 100755 index 000000000..1d34b9d0f --- /dev/null +++ b/scripts/authelia-scripts-suites-start @@ -0,0 +1,53 @@ +#!/usr/bin/env node + +var program = require('commander'); +var spawn = require('child_process').spawn; +var fs = require('fs'); + +let suite; + +program + .description(`Start the suite provided as argument. You can list the suites with the 'list' command.`) + .arguments('') + .action((suiteArg) => suite = suiteArg) + .parse(process.argv) + +if (!suite) { + program.help(); +} + +const ENVIRONMENT_FILENAME = '.suite'; + +let runEnvProcess; + +// Sometime SIGINT is received twice, we make sure with this variable that we cleanup +// only once. +var alreadyCleaningUp = false; + +// Properly cleanup server and client if ctrl-c is hit +process.on('SIGINT', function() { + if (alreadyCleaningUp) return; + alreadyCleaningUp = true; + console.log('Cleanup procedure is running...'); +}); + +async function main() { + fs.writeFileSync(ENVIRONMENT_FILENAME, suite); + + // Start the environment from ts-node process. + runEnvProcess = spawn('./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/run-environment.ts ' + suite, { + shell: true + }); + runEnvProcess.stdout.pipe(process.stdout); + runEnvProcess.stderr.pipe(process.stderr); + + runEnvProcess.on('exit', function(statusCode) { + fs.unlinkSync(ENVIRONMENT_FILENAME); + process.exit(statusCode); + }); +} + +main().catch((err) => { + console.error(err); + process.exit(1) +}); \ No newline at end of file diff --git a/scripts/authelia-scripts-suites-test b/scripts/authelia-scripts-suites-test new file mode 100755 index 000000000..0711d97af --- /dev/null +++ b/scripts/authelia-scripts-suites-test @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +var program = require('commander'); +var spawn = require('child_process').spawn; +var fs = require('fs'); + +let suite; + +program + .description('Run the tests for the current suite or the provided one.') + .arguments('[suite]') + .option('--headless', 'Run in headless mode.') + .action((suiteArg) => suite = suiteArg) + .parse(process.argv); + +let args = []; +const ENVIRONMENT_FILENAME = '.suite'; // This file is created by the start command. + +if (suite) { + if (fs.existsSync(ENVIRONMENT_FILENAME)) { + console.error('You cannot test a suite while another one is running. If you want to test the current suite, ' + + 'do not provide the suite argument. Otherwise, stop the current suite and run the command again.'); + process.exit(1); + } + console.log('Suite %s provided. Running test related to this suite against built version of Authelia.', suite); + args.push('test/suites/' + suite + '/test.ts'); +} +else if (fs.existsSync(ENVIRONMENT_FILENAME)) { + suite = fs.readFileSync(ENVIRONMENT_FILENAME); + console.log('Suite %s detected from dev env. Running test related to this suite.', suite); + args.push('test/suites/' + suite + '/test.ts'); +} +else { + console.log('No suite provided therefore all suites will be tested.'); + args.push('test/suites/**/test.ts'); +} + +mocha = spawn('./node_modules/.bin/mocha', ['--exit', '--colors', '--require', 'ts-node/register', ...args], { + env: { + ...process.env, + TS_NODE_PROJECT: 'test/tsconfig.json', + HEADLESS: (program.headless) ? 'y' : 'n', + } +}); + +mocha.stdout.pipe(process.stdout); +mocha.stderr.pipe(process.stderr); + +mocha.on('exit', function(statusCode) { + if (statusCode != 0) { + console.error("The tests failed... Mocha exited with status code " + statusCode); + fs.readFile('/tmp/authelia-server.log', function(err, data) { + if (err) { + console.error(err); + return; + } + console.log(data.toString('utf-8')); + }); + } + process.exit(statusCode); +}) diff --git a/scripts/authelia-scripts-test b/scripts/authelia-scripts-test deleted file mode 100755 index e7d19b3d7..000000000 --- a/scripts/authelia-scripts-test +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env node - -var program = require('commander'); -var spawn = require('child_process').spawn; -var fs = require('fs'); -var execSync = require('child_process').execSync; - -program - .option('--headless', 'Run in headless mode.') - .parse(process.argv); - -let withServer = false; -let args = []; -const ENVIRONMENT_FILENAME = '.suite'; // This file is created by the start command. - -if (fs.existsSync(ENVIRONMENT_FILENAME)) { - const suite = fs.readFileSync(ENVIRONMENT_FILENAME); - console.log('Suite %s detected (dev env running). Running test related to this suite.', suite); - args.push('test/suites/' + suite + '/*.ts'); -} -else if (program.args.length > 0) { - console.log('No suite detected. Running selected tests against built server.'); - withServer = true; - args = program.args; - - // Render the production version of the nginx portal configuration - execSync('./example/compose/nginx/portal/render.js --production'); - // Prepare the environment - execSync('./scripts/utils/prepare-environment.sh'); -} -else { - console.log('No suite detected but no tests have been selected...'); - process.exit(1); -} - -mocha = spawn('./node_modules/.bin/mocha', ['--exit', '--colors', '--require', 'ts-node/register', ...args], { - env: { - ...process.env, - TS_NODE_PROJECT: 'test/tsconfig.json', - WITH_SERVER: (withServer) ? 'y' : 'n', - HEADLESS: (program.headless) ? 'y' : 'n', - } -}); - -mocha.stdout.on('data', (data) => { - process.stdout.write(`${data}`); -}); - -mocha.stderr.on('data', (data) => { - process.stderr.write(`${data}`); -}); - -mocha.on('exit', function(statusCode) { - if (statusCode != 0) { - console.error("The tests failed... Mocha exited with status code " + statusCode); - fs.readFile('/tmp/authelia-server.log', function(err, data) { - if (err) { - console.error(err); - return; - } - console.log(data.toString('utf-8')); - }); - } - process.exit(statusCode); -}) diff --git a/scripts/authelia-scripts-travis b/scripts/authelia-scripts-travis index 8b7ce2767..7527d3a6d 100755 --- a/scripts/authelia-scripts-travis +++ b/scripts/authelia-scripts-travis @@ -19,7 +19,7 @@ authelia-scripts unittest authelia-scripts docker build # Run integration tests -authelia-scripts test --headless test/suites/**/*.ts +authelia-scripts suites test --headless # Test npm deployment before actual deployment # ./scripts/npm-deployment-test.sh diff --git a/scripts/clean-environment.ts b/scripts/clean-environment.ts new file mode 100644 index 000000000..0a874ebf5 --- /dev/null +++ b/scripts/clean-environment.ts @@ -0,0 +1,8 @@ +var ListSuites = require('./utils/ListSuites'); + +const suites = ListSuites(); + +suites.forEach(async (suite: string) => { + var { teardown } = require(`../test/suites/${suite}/environment`);; + teardown().catch((err: Error) => console.error(err)); +}); \ No newline at end of file diff --git a/scripts/dc-dev.sh b/scripts/dc-dev.sh deleted file mode 100755 index 0efb5db64..000000000 --- a/scripts/dc-dev.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -e - -docker-compose \ - -f docker-compose.yml \ - -f example/compose/mongo/docker-compose.yml \ - -f example/compose/redis/docker-compose.yml \ - -f example/compose/nginx/backend/docker-compose.yml \ - -f example/compose/nginx/portal/docker-compose.yml \ - -f example/compose/smtp/docker-compose.yml \ - -f example/compose/httpbin/docker-compose.yml \ - -f example/compose/ldap/docker-compose.admin.yml \ - -f example/compose/ldap/docker-compose.yml $* diff --git a/scripts/run-dev-server.sh b/scripts/run-dev-server.sh deleted file mode 100755 index 707e628c7..000000000 --- a/scripts/run-dev-server.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# Starts the server with the provided configuration in $1 -# This scripts is called from authelia-scripts. - -./node_modules/.bin/ts-node -P ./server/tsconfig.json ./server/src/index.ts $* diff --git a/scripts/run-environment.ts b/scripts/run-environment.ts new file mode 100644 index 000000000..ed1655e94 --- /dev/null +++ b/scripts/run-environment.ts @@ -0,0 +1,40 @@ + +const userSuite = process.argv[2]; + +var { setup, teardown } = require(`../test/suites/${userSuite}/environment`); + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +let teardownInProgress = false; + +process.on('SIGINT', function() { + if (teardownInProgress) return; + teardownInProgress = true; + console.log('Tearing down environment...'); + return teardown() + .then(() => { + process.exit(0) + }) + .catch((err: Error) => { + console.error(err); + process.exit(1); + }); +}); + +function main() { + console.log('Setting up environment...'); + return setup() + .then(async () => { + while (true) { + await sleep(10000); + } + }) + .catch((err: Error) => { + console.error(err); + process.exit(1); + }); +} + +main(); \ No newline at end of file diff --git a/scripts/utils/ListSuites.js b/scripts/utils/ListSuites.js new file mode 100644 index 000000000..546d05f8e --- /dev/null +++ b/scripts/utils/ListSuites.js @@ -0,0 +1,13 @@ +const { lstatSync, readdirSync } = require('fs') +const { join } = require('path') + +const isDirectory = source => lstatSync(source).isDirectory() +const getDirectories = source => + readdirSync(source) + .map(name => join(source, name)) + .filter(isDirectory) + .map(x => x.split('/').slice(-1)[0]) + +module.exports = function() { + return getDirectories('test/suites/'); +} \ No newline at end of file diff --git a/scripts/utils/prepare-environment.sh b/scripts/utils/prepare-environment.sh deleted file mode 100755 index cd17a6935..000000000 --- a/scripts/utils/prepare-environment.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -./scripts/dc-dev.sh up -d -./scripts/dc-dev.sh kill -s SIGHUP nginx-portal diff --git a/test/helpers/context/AutheliaServer.ts b/test/helpers/context/AutheliaServer.ts new file mode 100644 index 000000000..e14eedeb1 --- /dev/null +++ b/test/helpers/context/AutheliaServer.ts @@ -0,0 +1,26 @@ +import fs from 'fs'; +import AutheliaServerWithHotReload from "./AutheliaServerWithHotReload"; +import AutheliaServerInterface from './AutheliaServerInterface'; +import AutheliaServerFromDist from './AutheliaServerFromDist'; + +class AutheliaServer implements AutheliaServerInterface { + private runnerImpl: AutheliaServerInterface; + + constructor(configPath: string) { + if (fs.existsSync('.suite')) { + this.runnerImpl = new AutheliaServerWithHotReload(configPath); + } else { + this.runnerImpl = new AutheliaServerFromDist(configPath, true); + } + } + + async start() { + await this.runnerImpl.start(); + } + + async stop() { + await this.runnerImpl.stop(); + } +} + +export default AutheliaServer; \ No newline at end of file diff --git a/test/helpers/context/AutheliaServerFromDist.ts b/test/helpers/context/AutheliaServerFromDist.ts new file mode 100644 index 000000000..3a347b37f --- /dev/null +++ b/test/helpers/context/AutheliaServerFromDist.ts @@ -0,0 +1,39 @@ +import AutheliaServerInterface from './AutheliaServerInterface'; +import ChildProcess from 'child_process'; +import treeKill = require('tree-kill'); +import fs from 'fs'; + +class AutheliaServerFromDist implements AutheliaServerInterface { + private configPath: string; + private logInFile: boolean; + private serverProcess: ChildProcess.ChildProcess | undefined; + + constructor(configPath: string, logInFile: boolean = false) { + this.configPath = configPath; + this.logInFile = logInFile; + } + + async start() { + this.serverProcess = ChildProcess.spawn('./scripts/authelia-scripts serve ' + this.configPath, { + shell: true + } as any); + if (this.logInFile) { + var logStream = fs.createWriteStream('/tmp/authelia-server.log', {flags: 'a'}); + this.serverProcess.stdout.pipe(logStream); + this.serverProcess.stderr.pipe(logStream); + } else { + this.serverProcess.stdout.pipe(process.stdout); + this.serverProcess.stderr.pipe(process.stderr); + } + this.serverProcess.on('exit', (statusCode) => { + console.log('Authelia server exited with code ' + statusCode); + }) + } + + async stop() { + if (!this.serverProcess) return; + treeKill(this.serverProcess.pid, 'SIGKILL'); + } +} + +export default AutheliaServerFromDist; \ No newline at end of file diff --git a/test/helpers/context/AutheliaServerInterface.ts b/test/helpers/context/AutheliaServerInterface.ts new file mode 100644 index 000000000..5ac11a54a --- /dev/null +++ b/test/helpers/context/AutheliaServerInterface.ts @@ -0,0 +1,7 @@ + +interface AutheliaServerInterface { + start(): Promise; + stop(): Promise +} + +export default AutheliaServerInterface; \ No newline at end of file diff --git a/test/helpers/context/AutheliaServerWithHotReload.ts b/test/helpers/context/AutheliaServerWithHotReload.ts new file mode 100644 index 000000000..7a0ec8fe0 --- /dev/null +++ b/test/helpers/context/AutheliaServerWithHotReload.ts @@ -0,0 +1,149 @@ +import Chokidar from 'chokidar'; +import fs from 'fs'; +import { exec } from '../utils/exec'; +import ChildProcess from 'child_process'; +import kill from 'tree-kill'; +import AutheliaServerInterface from './AutheliaServerInterface'; + +class AutheliaServerWithHotReload implements AutheliaServerInterface { + private watcher: Chokidar.FSWatcher; + private configPath: string; + private AUTHELIA_INTERRUPT_FILENAME = '.authelia-interrupt'; + private serverProcess: ChildProcess.ChildProcess | undefined; + private clientProcess: ChildProcess.ChildProcess | undefined; + + constructor(configPath: string) { + this.configPath = configPath; + this.watcher = Chokidar.watch(['server', 'shared/**/*.ts', 'node_modules', + this.AUTHELIA_INTERRUPT_FILENAME, configPath], { + persistent: true, + ignoreInitial: true, + }); + } + + private async startServer() { + await exec('./node_modules/.bin/tslint -c server/tslint.json -p server/tsconfig.json') + this.serverProcess = ChildProcess.spawn('./node_modules/.bin/ts-node', + ['-P', './server/tsconfig.json', './server/src/index.ts', this.configPath], { + env: {...process.env}, + }); + this.serverProcess.stdout.pipe(process.stdout); + this.serverProcess.stderr.pipe(process.stderr); + this.serverProcess.on('exit', () => { + console.log('Authelia server exited.'); + if (!this.serverProcess) return; + this.serverProcess.removeAllListeners(); + this.serverProcess = undefined; + }); + } + + private killServer() { + return new Promise((resolve, reject) => { + if (this.serverProcess) { + try { + const timeout = setTimeout( + () => reject(new Error('Server not killed after timeout.')), 10000); + this.serverProcess.on('exit', () => { + clearTimeout(timeout); + resolve(); + }); + kill(this.serverProcess.pid, 'SIGKILL'); + } catch (e) { + reject(e); + } + } else { + resolve(); + } + }); + } + + private async startClient() { + this.clientProcess = ChildProcess.spawn('npm', ['run', 'start'], { + cwd: './client', + env: { + ...process.env, + 'BROWSER': 'none' + } + }); + this.clientProcess.stdout.pipe(process.stdout); + this.clientProcess.stderr.pipe(process.stderr); + this.clientProcess.on('exit', () => { + console.log('Authelia client exited.'); + if (!this.clientProcess) return; + this.clientProcess.removeAllListeners(); + this.clientProcess = undefined; + }) + } + + private killClient() { + return new Promise((resolve, reject) => { + if (this.clientProcess) { + try { + const timeout = setTimeout( + () => reject(new Error('Server not killed after timeout.')), 10000); + this.clientProcess.on('exit', () => { + clearTimeout(timeout); + resolve(); + }); + kill(this.clientProcess.pid, 'SIGKILL'); + } catch (e) { + reject(e); + } + } else { + resolve(); + } + }); + } + + private async generateConfigurationSchema() { + await exec('./node_modules/.bin/typescript-json-schema -o ' + + 'server/src/lib/configuration/Configuration.schema.json ' + + '--strictNullChecks --required server/tsconfig.json Configuration'); + } + + /** + * Handle file changes. + * @param path The path of the file that has been changed. + */ + private async onFileChanged(path: string) { + console.log(`File ${path} has been changed, reloading...`); + if (path.startsWith('server/src/lib/configuration/schema')) { + console.log('Schema needs to be regenerated.'); + await this.generateConfigurationSchema(); + } + else if (path === this.AUTHELIA_INTERRUPT_FILENAME) { + if (fs.existsSync(path)) { + console.log('Authelia is being interrupted.'); + await this.killServer(); + } else { + console.log('Authelia is restarting.'); + await this.startServer(); + } + return; + } + await this.killServer(); + await this.startServer(); + } + + async start() { + if (fs.existsSync(this.AUTHELIA_INTERRUPT_FILENAME)) { + console.log('Authelia is interrupted. Consider removing ' + this.AUTHELIA_INTERRUPT_FILENAME + ' if it\'s not expected.'); + return; + } + + console.log('Start watching file changes...'); + this.watcher.on('add', (p) => this.onFileChanged(p)); + this.watcher.on('unlink', (p) => this.onFileChanged(p)); + this.watcher.on('change', (p) => this.onFileChanged(p)); + + this.startClient(); + this.startServer(); + } + + async stop() { + await this.killClient(); + await this.killServer(); + } +} + +export default AutheliaServerWithHotReload; \ No newline at end of file diff --git a/test/helpers/context/AutheliaSuite.ts b/test/helpers/context/AutheliaSuite.ts index 53b621852..f4d92bc8c 100644 --- a/test/helpers/context/AutheliaSuite.ts +++ b/test/helpers/context/AutheliaSuite.ts @@ -1,16 +1,17 @@ -import WithAutheliaRunning from "./WithAutheliaRunning"; +import WithEnvironment from "./WithEnvironment"; +import fs from 'fs'; interface AutheliaSuiteType { (description: string, configPath: string, cb: (this: Mocha.ISuiteCallbackContext) => void): Mocha.ISuite; only: (description: string, configPath: string, cb: (this: Mocha.ISuiteCallbackContext) => void) => Mocha.ISuite; } -function AutheliaSuiteBase(description: string, configPath: string, +function AutheliaSuiteBase(description: string, suite: string, cb: (this: Mocha.ISuiteCallbackContext) => void, context: (description: string, ctx: (this: Mocha.ISuiteCallbackContext) => void) => Mocha.ISuite) { return context('Suite: ' + description, function(this: Mocha.ISuiteCallbackContext) { - if (process.env['WITH_SERVER'] == 'y') { - WithAutheliaRunning(configPath); + if (!fs.existsSync('.suite')) { + WithEnvironment(suite); } cb.call(this); diff --git a/test/helpers/context/DockerCompose.ts b/test/helpers/context/DockerCompose.ts new file mode 100644 index 000000000..742fe41bf --- /dev/null +++ b/test/helpers/context/DockerCompose.ts @@ -0,0 +1,23 @@ +import { exec } from '../../helpers/utils/exec'; + +class DockerCompose { + private commandPrefix: string; + + constructor(composeFiles: string[]) { + this.commandPrefix = 'docker-compose ' + composeFiles.map((f) => '-f ' + f).join(' '); + } + + async up() { + await exec(this.commandPrefix + ' up -d'); + } + + async down() { + await exec(this.commandPrefix + ' down'); + } + + async restart(service: string) { + await exec(this.commandPrefix + ' restart ' + service); + } +} + +export default DockerCompose; \ No newline at end of file diff --git a/test/helpers/context/DockerEnvironment.ts b/test/helpers/context/DockerEnvironment.ts new file mode 100644 index 000000000..5d3f1e764 --- /dev/null +++ b/test/helpers/context/DockerEnvironment.ts @@ -0,0 +1,19 @@ +import DockerCompose from "./DockerCompose"; + +class DockerEnvironment { + private dockerCompose: DockerCompose; + + constructor(composeFiles: string[]) { + this.dockerCompose = new DockerCompose(composeFiles); + } + + async start() { + await this.dockerCompose.up(); + } + + async stop() { + await this.dockerCompose.down(); + } +} + +export default DockerEnvironment; \ No newline at end of file diff --git a/test/helpers/context/WithAutheliaRunning.ts b/test/helpers/context/WithAutheliaRunning.ts deleted file mode 100644 index 0edd14898..000000000 --- a/test/helpers/context/WithAutheliaRunning.ts +++ /dev/null @@ -1,44 +0,0 @@ - -import ChildProcess from 'child_process'; -import fs from 'fs'; - -export default function WithAutheliaRunning(configPath: string, waitTimeout: number = 5000) { - before(function() { - this.timeout(10000); - - console.log('Spawning Authelia server with configuration %s.', configPath); - const authelia = ChildProcess.spawn( - './scripts/authelia-scripts', - ['serve', '--no-watch', '--config', configPath], - {detached: true}); - - authelia.on('exit', function(statusCode) { - console.log('Server terminated with status ' + statusCode); - if (statusCode != 0) { - fs.readFile('/tmp/authelia-server.log', function(err, data) { - if (err) { - console.error(err); - return; - } - console.log(data.toString('utf-8')); - }) - } - }); - this.authelia = authelia; - - const waitPromise = new Promise((resolve, reject) => setTimeout(() => resolve(), waitTimeout)); - return waitPromise; - }); - - after(function() { - this.timeout(10000); - - console.log('Killing Authelia server.'); - // Kill the group of processes. - process.kill(-this.authelia.pid); - - // Leave 5 seconds for the process to terminate. - const waitPromise = new Promise((resolve, reject) => setTimeout(() => resolve(), 5000)); - return waitPromise; - }); -} \ No newline at end of file diff --git a/test/helpers/context/WithEnvironment.ts b/test/helpers/context/WithEnvironment.ts new file mode 100644 index 000000000..c6fd9bdcd --- /dev/null +++ b/test/helpers/context/WithEnvironment.ts @@ -0,0 +1,23 @@ +import sleep from '../utils/sleep'; + +export default function WithAutheliaRunning(suitePath: string, waitTimeout: number = 5000) { + const suite = suitePath.split('/').slice(-1)[0]; + var { setup, teardown } = require(`../../suites/${suite}/environment`); + + before(async function() { + this.timeout(10000); + + console.log('Preparing environment...'); + await setup(); + await sleep(waitTimeout); + }); + + after(async function() { + this.timeout(10000); + + console.log('Stopping environment...'); + await teardown(); + + await sleep(waitTimeout); + }); +} \ No newline at end of file diff --git a/test/helpers/utils/exec.ts b/test/helpers/utils/exec.ts new file mode 100644 index 000000000..5fe77cc4e --- /dev/null +++ b/test/helpers/utils/exec.ts @@ -0,0 +1,20 @@ +var spawn = require('child_process').spawn; + + +export function exec(command: string): Promise { + return new Promise((resolve, reject) => { + const cmd = spawn(command, { + shell: true, + }); + + cmd.stdout.pipe(process.stdout); + cmd.stderr.pipe(process.stderr); + cmd.on('exit', (statusCode: number) => { + if (statusCode == 0) { + resolve(); + return; + } + reject(new Error('Exited with status code ' + statusCode)); + }); + }); +} diff --git a/test/helpers/utils/sleep.ts b/test/helpers/utils/sleep.ts new file mode 100644 index 000000000..d8321ed06 --- /dev/null +++ b/test/helpers/utils/sleep.ts @@ -0,0 +1,5 @@ + + +export default function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/test/suites/complete/environment.ts b/test/suites/complete/environment.ts new file mode 100644 index 000000000..de25d2f20 --- /dev/null +++ b/test/suites/complete/environment.ts @@ -0,0 +1,40 @@ +import DockerEnvironment from "../../helpers/context/DockerEnvironment"; +import AutheliaServer from "../../helpers/context/AutheliaServer"; +import { exec } from "../../helpers/utils/exec"; +import fs from 'fs'; + +const composeFiles = [ + 'docker-compose.yml', + 'example/compose/mongo/docker-compose.yml', + 'example/compose/redis/docker-compose.yml', + 'example/compose/nginx/backend/docker-compose.yml', + 'example/compose/nginx/portal/docker-compose.yml', + 'example/compose/smtp/docker-compose.yml', + 'example/compose/httpbin/docker-compose.yml', + 'example/compose/ldap/docker-compose.admin.yml', // This is just used for administration, not for testing. + 'example/compose/ldap/docker-compose.yml' +] + +const dockerEnv = new DockerEnvironment(composeFiles); +const autheliaServer = new AutheliaServer(__dirname + '/config.yml'); + +async function setup() { + // In dev mode Authelia has the server served on one port and the frontend on another port. + await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); + + console.log(`Prepare environment with docker-compose...`); + await dockerEnv.start(); + + console.log('Start Authelia server.'); + await autheliaServer.start(); +} + +async function teardown() { + console.log('Stop Authelia server.'); + await autheliaServer.stop(); + + console.log(`Cleanup environment with docker-compose...`); + await dockerEnv.stop(); +} + +export { setup, teardown, composeFiles }; \ No newline at end of file diff --git a/test/suites/complete/scenarii/MongoConnectionRecovery.ts b/test/suites/complete/scenarii/MongoConnectionRecovery.ts index c6feab798..db72213dd 100644 --- a/test/suites/complete/scenarii/MongoConnectionRecovery.ts +++ b/test/suites/complete/scenarii/MongoConnectionRecovery.ts @@ -3,6 +3,8 @@ import FullLogin from "../../../helpers/FullLogin"; import child_process from 'child_process'; import WithDriver from "../../../helpers/context/WithDriver"; import Logout from "../../../helpers/Logout"; +import { composeFiles } from '../environment'; +import DockerCompose from "../../../helpers/context/DockerCompose"; export default function() { after(async function() { @@ -15,7 +17,8 @@ export default function() { this.timeout(30000); const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true); - child_process.execSync("./scripts/dc-dev.sh restart mongo"); + const dockerCompose = new DockerCompose(composeFiles); + await dockerCompose.restart('mongo'); await FullLogin(this.driver, "john", secret, "https://admin.example.com:8080/secret.html"); }); } \ No newline at end of file diff --git a/test/suites/complete/index.ts b/test/suites/complete/test.ts similarity index 91% rename from test/suites/complete/index.ts rename to test/suites/complete/test.ts index f11886b36..49d4447c8 100644 --- a/test/suites/complete/index.ts +++ b/test/suites/complete/test.ts @@ -8,11 +8,7 @@ import BasicAuthentication from "./scenarii/BasicAuthentication"; import AutheliaRestart from "./scenarii/AutheliaRestart"; import AuthenticationRegulation from "./scenarii/AuthenticationRegulation"; -before(function() { - -}); - -AutheliaSuite('Complete configuration', __dirname + '/config.yml', function() { +AutheliaSuite('Complete configuration', __dirname, function() { this.timeout(10000); describe('Custom headers forwarded to backend', CustomHeadersForwarded); diff --git a/test/suites/docker/environment.ts b/test/suites/docker/environment.ts new file mode 100644 index 000000000..e9aa70e60 --- /dev/null +++ b/test/suites/docker/environment.ts @@ -0,0 +1,18 @@ +import { exec } from '../../helpers/utils/exec'; +import ChildProcess from 'child_process'; + +async function setup() { + await exec('docker run -d -v $(pwd)/config.yml:/etc/authelia/config.yml --name authelia-test clems4ever/authelia > /dev/null'); + console.log('Container has been spawned.'); +} + +async function teardown() { + try { + ChildProcess.execSync('docker ps | grep "authelia-test"'); + await exec('docker rm -f authelia-test > /dev/null'); + } catch (e) { + // If grep does not find anything, execSync throws an exception since the command returns 1. + } +} + +export { setup, teardown }; \ No newline at end of file diff --git a/test/suites/docker/index.ts b/test/suites/docker/index.ts deleted file mode 100644 index 4e48c931f..000000000 --- a/test/suites/docker/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import ChildProcess from 'child_process'; -import Bluebird from 'bluebird'; -import Assert from 'assert'; - -const execAsync = Bluebird.promisify(ChildProcess.exec); - -function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -describe('Test docker container can run', function() { - this.timeout(15000); - - before(async function() { - await execAsync('docker run -d -v $(pwd)/config.yml:/etc/authelia/config.yml --name authelia-test clems4ever/authelia'); - }); - - after(async function() { - await execAsync('docker rm -f authelia-test'); - }); - - it('should be running', async function() { - await sleep(5000); - const output: string = await execAsync('docker ps -a | grep "authelia-test"'); - Assert(output.match(new RegExp('Up [0-9] seconds'))); - }); -}); \ No newline at end of file diff --git a/test/suites/docker/test.ts b/test/suites/docker/test.ts new file mode 100644 index 000000000..3004fccbc --- /dev/null +++ b/test/suites/docker/test.ts @@ -0,0 +1,17 @@ +import ChildProcess from 'child_process'; +import Bluebird from 'bluebird'; +import Assert from 'assert'; +import sleep from '../../helpers/utils/sleep'; +import AutheliaSuite from '../../helpers/context/AutheliaSuite'; + +const execAsync = Bluebird.promisify(ChildProcess.exec); + +AutheliaSuite('Test docker container runs as expected', __dirname, function() { + this.timeout(15000); + + it('should be running', async function() { + await sleep(5000); + const output: string = await execAsync('docker ps -a | grep "authelia-test"'); + Assert(output.match(new RegExp('Up [0-9]+ seconds'))); + }); +}); \ No newline at end of file diff --git a/test/suites/minimal/environment.ts b/test/suites/minimal/environment.ts new file mode 100644 index 000000000..3fb43625a --- /dev/null +++ b/test/suites/minimal/environment.ts @@ -0,0 +1,27 @@ +import fs from 'fs'; +import { exec } from "../../helpers/utils/exec"; +import AutheliaServer from "../../helpers/context/AutheliaServer"; +import DockerEnvironment from "../../helpers/context/DockerEnvironment"; + +const autheliaServer = new AutheliaServer(__dirname + '/config.yml'); +const dockerEnv = new DockerEnvironment([ + 'docker-compose.yml', + 'example/compose/nginx/backend/docker-compose.yml', + 'example/compose/nginx/portal/docker-compose.yml', + 'example/compose/smtp/docker-compose.yml', +]) + +async function setup() { + await exec('mkdir -p /tmp/authelia/db'); + await exec('./example/compose/nginx/portal/render.js ' + (fs.existsSync('.suite') ? '': '--production')); + await dockerEnv.start(); + await autheliaServer.start(); +} + +async function teardown() { + await dockerEnv.stop(); + await autheliaServer.stop(); + await exec('mkdir -p /tmp/authelia/db'); +} + +export { setup, teardown }; \ No newline at end of file diff --git a/test/suites/minimal/index.ts b/test/suites/minimal/test.ts similarity index 74% rename from test/suites/minimal/index.ts rename to test/suites/minimal/test.ts index 92654ce04..910221d01 100644 --- a/test/suites/minimal/index.ts +++ b/test/suites/minimal/test.ts @@ -1,6 +1,3 @@ -import ChildProcess from 'child_process'; -import Bluebird from "bluebird"; - import AutheliaSuite from "../../helpers/context/AutheliaSuite"; import BadPassword from "./scenarii/BadPassword"; import RegisterTotp from './scenarii/RegisterTotp'; @@ -12,21 +9,12 @@ import VerifyEndpoint from './scenarii/VerifyEndpoint'; import RequiredTwoFactor from './scenarii/RequiredTwoFactor'; import LogoutRedirectToAlreadyLoggedIn from './scenarii/LogoutRedirectToAlreadyLoggedIn'; import SimpleAuthentication from './scenarii/SimpleAuthentication'; +import { exec } from '../../helpers/utils/exec'; -const execAsync = Bluebird.promisify(ChildProcess.exec); - -before(async function() { - await execAsync('mkdir -p /tmp/authelia/db'); -}); - -after(async function() { - await execAsync('rm -r /tmp/authelia/db'); -}); - -AutheliaSuite('Minimal configuration', __dirname + '/config.yml', function() { +AutheliaSuite('Minimal configuration', __dirname, function() { this.timeout(10000); beforeEach(async function() { - await execAsync('cp users_database.example.yml users_database.yml'); + await exec('cp users_database.example.yml users_database.yml'); }); describe('Simple authentication', SimpleAuthentication); diff --git a/test/tsconfig.json b/test/tsconfig.json index c256a6110..66fabf625 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -10,7 +10,7 @@ "module": "commonjs", "moduleResolution": "node", "resolveJsonModule": true, - "isolatedModules": true, + "isolatedModules": false, "noEmit": true, "lib": [ "esnext"