changes to the testing, incorporating browser_testing
This commit is contained in:
15
.travis.yml
15
.travis.yml
@ -5,18 +5,21 @@ matrix:
|
||||
- node_js: "0.8"
|
||||
env: ES_BRANCH=master
|
||||
- node_js: "0.10"
|
||||
env: ES_BRANCH=master COVERAGE=true
|
||||
env: ES_BRANCH=master COVERAGE=1
|
||||
- node_js: "0.10"
|
||||
env: ES_BRANCH=0.90 NO_UNIT=true
|
||||
env: ES_BRANCH=0.90 NODE_UNIT=0
|
||||
- node_js: "0.10"
|
||||
env: ES_RELEASE=0.90.9 ES_BRANCH=0.90 NO_UNIT=true
|
||||
env: ES_RELEASE=0.90.9 ES_BRANCH=0.90 NODE_UNIT=0
|
||||
- node_js: "0.10"
|
||||
env: ES_RELEASE=0.90.8 ES_BRANCH=0.90 NO_UNIT=true
|
||||
|
||||
env: ES_RELEASE=0.90.8 ES_BRANCH=0.90 NODE_UNIT=0
|
||||
- node_js: "0.10"
|
||||
env: NODE_UNIT=0 NODE_INTEGRATION=0 TEST_BROWSER='firefox::Windows\ XP'
|
||||
- node_js: "0.10"
|
||||
env: NODE_UNIT=0 NODE_INTEGRATION=0 TEST_BROWSER='chrome::Windows\ XP'
|
||||
exclude:
|
||||
- node_js: false
|
||||
|
||||
script: ./scripts/travis.sh
|
||||
script: ./scripts/ci.sh
|
||||
email:
|
||||
recipients:
|
||||
- spencer.alger@elasticsearch.com
|
||||
|
||||
@ -46,7 +46,9 @@
|
||||
"grunt-mocha-cov": "~0.1.1",
|
||||
"grunt-open": "~0.2.2",
|
||||
"glob": "~3.2.7",
|
||||
"expect.js": "~0.2.0"
|
||||
"expect.js": "~0.2.0",
|
||||
"aliasify": "~1.2.1",
|
||||
"express": "~3.4.7"
|
||||
},
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
module.exports = function (argv, steps) {
|
||||
|
||||
var async = require('async');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var format = require('util').format;
|
||||
var cp = require('child_process');
|
||||
|
||||
function log() {
|
||||
var out = format.apply(console, arguments);
|
||||
if (argv.verbose) {
|
||||
out = '\n' + out + '\n';
|
||||
}
|
||||
console.log(out);
|
||||
}
|
||||
|
||||
var tasks = {
|
||||
exec: function (params, done) {
|
||||
var cmd = params.cmd;
|
||||
var opts = {};
|
||||
|
||||
if (params.cwd) {
|
||||
opts.cwd = path.resolve(params.cwd);
|
||||
}
|
||||
|
||||
log('running', cmd, (opts.cwd ? 'in ' + opts.cwd : ''));
|
||||
|
||||
cp.exec(cmd, opts, function (err, stdout, stderr) {
|
||||
stdout = stdout.trim();
|
||||
stderr = stderr.trim();
|
||||
|
||||
if (err) {
|
||||
console.error('Error! status:', err.code, ' -----\n' + err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
else {
|
||||
if (argv.verbose) {
|
||||
if (stderr) {
|
||||
console.error('----------- STDERR -----------');
|
||||
console.error(stdout);
|
||||
console.error('------------------------------');
|
||||
}
|
||||
console.log(stdout);
|
||||
}
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
run: function (params, done) {
|
||||
var cmd = params.cmd;
|
||||
var args = params.args || [];
|
||||
var opts = {
|
||||
stdio: argv.verbose ? 'inherit' : 'ignore'
|
||||
};
|
||||
|
||||
if (params.cwd) {
|
||||
opts.cwd = path.resolve(params.cwd);
|
||||
}
|
||||
|
||||
log('running', cmd, args.join(' '), (opts.cwd ? 'in ' + opts.cwd : ''));
|
||||
|
||||
var proc = cp.spawn(cmd, args, opts);
|
||||
|
||||
proc.on('error', function (err) {
|
||||
console.error('Error! --', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
proc.on('exit', function (status) {
|
||||
if (status) {
|
||||
console.error('Error! --', cmd, 'exit status was', status);
|
||||
process.exit(1);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
runInModule: function (params, done) {
|
||||
params = params || {};
|
||||
params.cwd = path.resolve(__dirname, '../');
|
||||
this.run(params, done);
|
||||
},
|
||||
copy: function (params, done) {
|
||||
var from = params.from;
|
||||
var to = params.to;
|
||||
|
||||
log('copying', from, 'to', to);
|
||||
|
||||
var read = fs.createReadStream(from);
|
||||
var write = fs.createWriteStream(to);
|
||||
|
||||
read.pipe(write);
|
||||
|
||||
read.on('error', function (err) {
|
||||
console.error('unable to read: ' + from);
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
write.on('error', function (err) {
|
||||
console.error('unable to write to: ' + to);
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
write.on('finish', function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async.forEachSeries(steps, function (args, done) {
|
||||
// pass the callback to the task
|
||||
args.push(done);
|
||||
|
||||
// get the task name
|
||||
var taskName = args.shift();
|
||||
|
||||
// find the task
|
||||
var task = tasks;
|
||||
taskName.split('.').forEach(function (name) {
|
||||
if (task && task[name]) {
|
||||
task = task[name];
|
||||
} else {
|
||||
throw new Error(taskName + ' is an invalid task, unable to get ' + name + ' from ' + task);
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof task === 'function') {
|
||||
task.apply(tasks, args);
|
||||
} else {
|
||||
throw new Error(taskName + ' is an invalid task, does not resolve to a function.');
|
||||
}
|
||||
}, function () {
|
||||
console.log('✔︎');
|
||||
process.exit();
|
||||
});
|
||||
|
||||
};
|
||||
13
scripts/browser_tests.js
Normal file
13
scripts/browser_tests.js
Normal file
@ -0,0 +1,13 @@
|
||||
var argv = require('optimist')
|
||||
.options({
|
||||
browser: {
|
||||
default: null,
|
||||
string: true
|
||||
},
|
||||
es_branch: {
|
||||
default: 'master',
|
||||
string: true
|
||||
}
|
||||
}).argv;
|
||||
|
||||
console.log(argv);
|
||||
156
scripts/ci.sh
Executable file
156
scripts/ci.sh
Executable file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
###########
|
||||
# Run the tests, and setup es if needed
|
||||
#
|
||||
# ENV VARS:
|
||||
# TRAVIS - Identifies that we're running on travis-ci
|
||||
# ES_V - version identifier set by Jenkins
|
||||
# ES_BRANCH - the ES branch we should use to generate the tests and download es
|
||||
# ES_VERSION - a specific ES version to download in use for testing
|
||||
# NODE_UNIT=1 - 0/1 run the unit tests in node
|
||||
# NODE_INTEGRATION=1 - 0/1 run the integration tests in node
|
||||
# TEST_BROWSER - the browser to run using selemium '{{name}}:{{version}}:{{OS}}'
|
||||
# COVERAGE - 0/1 check for coverage and ship it to coveralls
|
||||
#
|
||||
###########
|
||||
|
||||
#####
|
||||
# Start or stop a group for travis
|
||||
#####
|
||||
function group {
|
||||
if [ -n "$TRAVIS" ]; then
|
||||
echo -e "travis_fold:$1"
|
||||
fi
|
||||
}
|
||||
|
||||
#####
|
||||
# Do, log, and check a call
|
||||
#####
|
||||
function call {
|
||||
DO="$*"
|
||||
echo -e "\$ ${DO}"
|
||||
$DO
|
||||
RESULT=$?
|
||||
if [ "$RESULT" -gt "0" ]; then
|
||||
echo "non-zero exit code: $RESULT"
|
||||
exit $RESULT
|
||||
fi
|
||||
}
|
||||
|
||||
#####
|
||||
# call grunt, but make sure it exists first
|
||||
#####
|
||||
function grunt_ {
|
||||
DO="$*"
|
||||
|
||||
if [ ! -x "`which grunt`" ]; then
|
||||
group "start:install_grunt"
|
||||
echo "installing grunt-cli"
|
||||
call npm install -g grunt-cli
|
||||
group "end:install_grunt"
|
||||
fi
|
||||
|
||||
call grunt $DO
|
||||
}
|
||||
|
||||
#####
|
||||
# Download a version of ES and get it running
|
||||
# @arg ES_BRANCH - The branch to run off of
|
||||
# @arg ES_RELEASE - The specific release to run, overrides ES_BRANCH
|
||||
#####
|
||||
function get_es {
|
||||
group "start:setup_es"
|
||||
ES_BRANCH=$1
|
||||
ES_RELEASE=$2
|
||||
|
||||
ROOT="$PWD"
|
||||
ES_SUBMODULE="$ROOT/src/elasticsearch"
|
||||
SNAPSHOTS="$ROOT/.snapshots"
|
||||
|
||||
if [ ! -d "$SNAPSHOTS" ]; then
|
||||
mkdir $SNAPSHOTS
|
||||
fi
|
||||
|
||||
if [ ! -z $ES_RELEASE ]; then
|
||||
ES_VERSION="v${ES_RELEASE}"
|
||||
ES_URL="https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-${ES_RELEASE}.zip"
|
||||
ES_DIR="${SNAPSHOTS}/${ES_VERSION}"
|
||||
else
|
||||
ES_VERSION="${ES_BRANCH}_nightly"
|
||||
ES_URL="http://s3-us-west-2.amazonaws.com/build.elasticsearch.org/origin/$ES_BRANCH/nightly/JDK6/elasticsearch-latest-SNAPSHOT.zip"
|
||||
DATE=`date +%Y_%m_%d`
|
||||
ES_DIR="${SNAPSHOTS}/${ES_VERSION}_${DATE}"
|
||||
if [ ! -d $ES_DIR ]; then
|
||||
call rm -rf ${SNAPSHOTS}/${ES_VERSION}*
|
||||
fi
|
||||
fi
|
||||
|
||||
ES_BIN="$ES_DIR/bin/elasticsearch"
|
||||
|
||||
echo "Killing existsing java processes"
|
||||
killall java 2>/dev/null
|
||||
|
||||
cd $SNAPSHOTS
|
||||
|
||||
if [ ! -d "$ES_DIR" ]; then
|
||||
echo "Downloading Elasticsearch $ES_VERSION"
|
||||
call curl -#O $ES_URL
|
||||
call unzip -q elasticsearch-*.zip
|
||||
call rm elasticsearch-*.zip
|
||||
call mv elasticsearch-*/ $ES_DIR
|
||||
fi
|
||||
|
||||
cd $ROOT
|
||||
|
||||
if [ ! -x "$ES_BIN" ]; then
|
||||
echo "Unable to find elasticsearch executable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$ES_BRANCH" = "0.90" ]; then
|
||||
echo "Starting Elasticsearch $ES_VERSION"
|
||||
call $ES_BIN \
|
||||
-Des.network.host=localhost \
|
||||
-Des.discovery.zen.ping.multicast.enabled=false \
|
||||
-Des.discovery.zen.ping_timeout=1
|
||||
else
|
||||
echo "Starting Elasticsearch $ES_VERSION as a deamon"
|
||||
call $ES_BIN -d \
|
||||
-Des.network.host=localhost \
|
||||
-Des.discovery.zen.ping.multicast.enabled=false \
|
||||
-Des.discovery.zen.ping_timeout=1
|
||||
fi
|
||||
group "end:setup_es"
|
||||
}
|
||||
|
||||
if [ -n "$ES_BRANCH" ]; then
|
||||
TESTING_BRANCH=$ES_BRANCH
|
||||
else if [ -n "$ES_V" ]; then
|
||||
TESTING_BRANCH=$ES_V
|
||||
else
|
||||
TESTING_BRANCH="master"
|
||||
fi
|
||||
|
||||
if [[ $NODE_UNIT -eq 1 ]]; then
|
||||
grunt_ jshint mochacov:unit
|
||||
fi
|
||||
|
||||
if [ flag $NODE_INTEGRATION ]; then
|
||||
if [ -n "$ES_BRANCH" ] && [[ $USER != "jenkins" ]]; then
|
||||
get_es $ES_BRANCH $ES_RELEASE
|
||||
fi
|
||||
|
||||
call node scripts/generate --no-api --es_branch=$TESTING_BRANCH
|
||||
grunt_ mochacov:integration
|
||||
fi
|
||||
|
||||
if [ -n "$TEST_BROWSER" ]; then
|
||||
call node scripts/browser_tests --browser=\"$TEST_BROWSER\" --es_branch=$TESTING_BRANCH
|
||||
fi
|
||||
|
||||
if [[ $COVERAGE -eq 1 ]]; then
|
||||
grunt_ mochacov:ship_coverage
|
||||
fi
|
||||
|
||||
killall java 2>/dev/null
|
||||
@ -1,116 +0,0 @@
|
||||
var server = require('./server');
|
||||
var _ = require('lodash');
|
||||
var open = require('open');
|
||||
var async = require('async');
|
||||
var chalk = require('chalk');
|
||||
|
||||
var browserAppNames = _.transform({
|
||||
safari: {
|
||||
darwin: 'Safari'
|
||||
},
|
||||
chrome: {
|
||||
darwin: 'Google Chrome',
|
||||
win32: 'Google Chrome',
|
||||
linux: 'google-chrome'
|
||||
},
|
||||
chromium: {
|
||||
linux: 'chromium-browser',
|
||||
},
|
||||
firefox: {
|
||||
darwin: 'Firefox',
|
||||
win32: 'Firefox',
|
||||
linux: 'firefox'
|
||||
},
|
||||
opera: {
|
||||
darwin: 'Opera',
|
||||
win32: 'Opera',
|
||||
linux: 'opera'
|
||||
}
|
||||
}, function (browserAppNames, config, name) {
|
||||
if (config[process.platform]) {
|
||||
browserAppNames[name] = config[process.platform];
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.platform !== 'darwin' && process.platform !== 'win32' && config.linux) {
|
||||
browserAppNames[name] = config.executable;
|
||||
return;
|
||||
}
|
||||
}, {});
|
||||
|
||||
var argv = require('optimist')
|
||||
.default({
|
||||
browsers: '*',
|
||||
forceGen: false,
|
||||
host: 'localhost',
|
||||
port: 9200
|
||||
})
|
||||
.boolean('forceGen')
|
||||
.alias({
|
||||
f: 'forceGen',
|
||||
b: 'browsers',
|
||||
h: 'host',
|
||||
p: 'port'
|
||||
})
|
||||
.argv;
|
||||
|
||||
server.browsers = [];
|
||||
|
||||
if (argv.browsers === '*') {
|
||||
server.browsers = _.keys(browserAppNames);
|
||||
} else {
|
||||
argv.browsers.split(',').forEach(function (browser) {
|
||||
server.browsers.push(browser);
|
||||
});
|
||||
}
|
||||
|
||||
var badKeys = _.difference(server.browsers, _.keys(browserAppNames));
|
||||
if (badKeys.length) {
|
||||
console.error('Invalid keys: ' + badKeys.join(', '));
|
||||
process.exit();
|
||||
} else {
|
||||
console.log('opening browser suite in', server.browsers);
|
||||
}
|
||||
|
||||
server.on('tests done', function (report) {
|
||||
var reports = [];
|
||||
var success = true;
|
||||
_.each(report, function (testSucceeded, browser) {
|
||||
var msg = browser + ':' + (success ? '✔︎' : '⚑');
|
||||
if (testSucceeded) {
|
||||
msg = chalk.green(msg);
|
||||
} else {
|
||||
msg = chalk.red(msg);
|
||||
success = false;
|
||||
}
|
||||
reports.push(' - ' + msg);
|
||||
});
|
||||
console.log('test completed!\n', reports.join('\n'));
|
||||
process.exit(success ? 0 : 1);
|
||||
});
|
||||
|
||||
async.series([
|
||||
function (done) {
|
||||
server.listen(0, function () {
|
||||
server.port = server.address().port;
|
||||
console.log('server listening on port', server.port);
|
||||
done();
|
||||
});
|
||||
},
|
||||
function (done) {
|
||||
async.eachSeries(_.clone(server.browsers), function (browser, browserDone) {
|
||||
open('http://localhost:' + server.port +
|
||||
'?es_hostname=' + encodeURIComponent(argv.host) +
|
||||
'&es_port=' + encodeURIComponent(argv.port) +
|
||||
'&browser=' + encodeURIComponent(browser), browserAppNames[browser]);
|
||||
|
||||
server.once('browser complete', _.bind(browserDone, null, null));
|
||||
}, done);
|
||||
}
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,220 +0,0 @@
|
||||
var http = require('http');
|
||||
var url = require('url');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var chalk = require('chalk');
|
||||
var makeJUnitXml = require('../../test/utils/make_j_unit_xml');
|
||||
var docRoot = path.join(__dirname, '../../test/integration/browser_yaml_suite');
|
||||
chalk.enabled = true;
|
||||
|
||||
var middleware = [];
|
||||
|
||||
Error.stackTraceLimit = Infinity;
|
||||
|
||||
var chars = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
var server = http.createServer(function (req, resp) {
|
||||
var parsedUrl = url.parse(req.url, true);
|
||||
req.uri = parsedUrl.pathname;
|
||||
req.query = parsedUrl.query;
|
||||
req.filename = path.join(docRoot, req.uri);
|
||||
|
||||
var end = resp.end;
|
||||
resp.end = function (data) {
|
||||
console.log(
|
||||
chalk[this.statusCode < 300 ? 'green' : 'red'](this.statusCode),
|
||||
req.uri,
|
||||
'-',
|
||||
Buffer.byteLength(data || ''),
|
||||
'bytes'
|
||||
);
|
||||
end.apply(resp, arguments);
|
||||
};
|
||||
|
||||
var middleIndex = -1;
|
||||
|
||||
function next() {
|
||||
middleIndex++;
|
||||
if (middleIndex < middleware.length) {
|
||||
middleware[middleIndex](req, resp, next);
|
||||
} else {
|
||||
resp.writeHead(500);
|
||||
resp.end('500 Bad Gateway\n');
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
server.browsers = [
|
||||
// browsers will go here, and will be removed once they call tests-complete
|
||||
// once gone, we will emit "tests done"
|
||||
];
|
||||
|
||||
function rand(length) {
|
||||
var str = '';
|
||||
while (str.length < length) {
|
||||
str += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function collectTestResults(req, resp) {
|
||||
var body = '';
|
||||
var browser = req.query.browser;
|
||||
var logFilename = 'test-output-' + browser + '.xml';
|
||||
|
||||
req.on('data', function (chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
req.on('error', function (err) {
|
||||
resp.writeHead(500);
|
||||
resp.end(err.message || 'failed to receive request completely');
|
||||
});
|
||||
|
||||
req.on('end', function () {
|
||||
var testDetails;
|
||||
try {
|
||||
testDetails = JSON.parse(body);
|
||||
} catch (e) {
|
||||
resp.writeHead(500);
|
||||
resp.end('encoding failure');
|
||||
return;
|
||||
}
|
||||
|
||||
resp.writeHead(200);
|
||||
resp.end('good work');
|
||||
|
||||
var xml = makeJUnitXml(browser, testDetails);
|
||||
fs.writeFile(logFilename, xml, function (err) {
|
||||
if (err) {
|
||||
console.log('unable to save test-output to', err.message);
|
||||
console.trace();
|
||||
browserComplete(browser);
|
||||
} else {
|
||||
console.log('test output written to', logFilename);
|
||||
browserComplete(browser, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var report = {};
|
||||
|
||||
function browserComplete(browser, success) {
|
||||
var i = server.browsers.indexOf(browser);
|
||||
report[browser] = success;
|
||||
server.emit('browser complete', browser, success);
|
||||
if (i >= 0) {
|
||||
server.browsers.splice(i, 1);
|
||||
if (server.browsers.length) {
|
||||
console.log('waiting for', server.browsers.length, 'browsers');
|
||||
} else {
|
||||
server.emit('tests done', report);
|
||||
}
|
||||
} else {
|
||||
console.error('invalid browser', browser);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
middleware.push(function (req, resp, next) {
|
||||
// resolve filenames
|
||||
switch (req.uri) {
|
||||
case '/tests-started':
|
||||
resp.end('OK');
|
||||
return;
|
||||
case '/tests-complete':
|
||||
return collectTestResults(req, resp);
|
||||
case '/expect.js':
|
||||
req.filename = path.join(__dirname, '../../node_modules/expect.js/expect.js');
|
||||
break;
|
||||
case '/mocha.js':
|
||||
case '/mocha.css':
|
||||
req.filename = path.join(__dirname, '../../node_modules/mocha', req.uri);
|
||||
break;
|
||||
case '/client.js':
|
||||
req.filename = path.join(__dirname, '../../dist/elasticsearch.js');
|
||||
break;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
middleware.push(function (req, resp, next) {
|
||||
// catch 404's, add directory's index.html
|
||||
fs.stat(req.filename, function (err, stats) {
|
||||
if (err) {
|
||||
resp.writeHead(404, {'Content-Type': 'text/plain'});
|
||||
resp.write('404 Not Found\n');
|
||||
resp.end();
|
||||
} else {
|
||||
if (stats.isDirectory()) {
|
||||
req.filename = path.join(docRoot, 'index.html');
|
||||
}
|
||||
next();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
middleware.push(function (req, resp) {
|
||||
// static files
|
||||
var reader = fs.createReadStream(req.filename);
|
||||
var data = '';
|
||||
|
||||
reader.on('data', onData);
|
||||
reader.on('error', onError);
|
||||
reader.on('end', onEnd);
|
||||
|
||||
function cleanupListeners() {
|
||||
reader.removeListener('end', onEnd);
|
||||
reader.removeListener('data', onData);
|
||||
reader.removeListener('error', onError);
|
||||
}
|
||||
|
||||
function onData(chunk) {
|
||||
data += chunk;
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
cleanupListeners();
|
||||
console.error(err);
|
||||
resp.setHeader('Content-Type', 'text/plain');
|
||||
resp.writeHead(500);
|
||||
resp.write(err.message + '\n');
|
||||
resp.end();
|
||||
}
|
||||
|
||||
function onEnd() {
|
||||
cleanupListeners();
|
||||
var contentType = 'text/plain';
|
||||
|
||||
switch (req.filename.split('.').pop()) {
|
||||
case 'js':
|
||||
contentType = 'application/javascript';
|
||||
break;
|
||||
case 'css':
|
||||
contentType = 'text/css';
|
||||
break;
|
||||
case 'html':
|
||||
contentType = 'text/html';
|
||||
break;
|
||||
}
|
||||
|
||||
if (contentType === 'text/html') {
|
||||
resp.end(_.template(data, _.defaults(req.query, {
|
||||
es_hostname: 'localhost',
|
||||
es_port: 9200,
|
||||
browser: 'unknown',
|
||||
ts: rand(5)
|
||||
})));
|
||||
} else {
|
||||
resp.end(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = server;
|
||||
@ -1,37 +0,0 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var argv = require('optimist')
|
||||
.default({
|
||||
verbose: false
|
||||
})
|
||||
.alias({
|
||||
v: 'verbose'
|
||||
})
|
||||
.argv;
|
||||
|
||||
var steps = [];
|
||||
|
||||
var cmd = argv._.join(' ');
|
||||
|
||||
if (!cmd) {
|
||||
throw new Error('you should specify a command...');
|
||||
}
|
||||
|
||||
['browser', 'jquery', 'angular'].forEach(function (build) {
|
||||
|
||||
if (!fs.existsSync('../bower-elasticsearch-' + build) ||
|
||||
!fs.existsSync('../bower-elasticsearch-' + build + '/.git')
|
||||
) {
|
||||
throw new Error('Ensure that all of the bower repos are checked out next to this repo');
|
||||
}
|
||||
|
||||
steps.push([
|
||||
'exec', {
|
||||
cmd: cmd,
|
||||
cwd: '../bower-elasticsearch-' + build
|
||||
}
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
require('./_steps')(argv, steps);
|
||||
@ -1,74 +0,0 @@
|
||||
var es = require('../src/elasticsearch');
|
||||
var async = require('async');
|
||||
var argv = require('optimist').default({
|
||||
indx: 'test-docs',
|
||||
type: 'test-doc',
|
||||
warm: 10000,
|
||||
docs: 100000,
|
||||
sync: false,
|
||||
sock: 100
|
||||
})
|
||||
.boolean('sync')
|
||||
.argv;
|
||||
|
||||
function hrtime(start) {
|
||||
var hr = start ? process.hrtime(start) : process.hrtime();
|
||||
return start ? Math.round(((hr[0] * 1e9 + hr[1]) / 1e6) * 100) / 100 : hr;
|
||||
}
|
||||
|
||||
var client = new es.Client({
|
||||
hosts: 'localhost:9200',
|
||||
log: null,
|
||||
maxSockets: argv.sock
|
||||
});
|
||||
|
||||
async.series([
|
||||
function (done) {
|
||||
console.log('removing existing "%s" index', argv.indx);
|
||||
client.indices.delete({
|
||||
index: argv.indx,
|
||||
ignore: 404
|
||||
}, done);
|
||||
},
|
||||
function (done) {
|
||||
console.log('creating new "%s" index', argv.indx);
|
||||
client.indices.create({
|
||||
index: argv.indx,
|
||||
body: {}
|
||||
}, done);
|
||||
},
|
||||
function (done) {
|
||||
console.log('warnming up index with %d docs', argv.warm);
|
||||
async.times(argv.warm, function (i, done) {
|
||||
client.index({
|
||||
index: argv.indx,
|
||||
type: argv.type,
|
||||
body: {}
|
||||
}, done);
|
||||
}, done);
|
||||
},
|
||||
function (done) {
|
||||
console.log('waiting for cluster to go yellow');
|
||||
client.cluster.health({
|
||||
waitForStatus: 'yellow'
|
||||
}, done);
|
||||
},
|
||||
function (done) {
|
||||
console.log('creating %d docs ' + (async.sync ? 'in series' : argv.sock + ' requests at a time'), argv.docs);
|
||||
var start = hrtime();
|
||||
async[argv.sync ? 'timesSeries' : 'times'](argv.docs, function (i, done) {
|
||||
client.index({
|
||||
index: argv.indx,
|
||||
type: argv.type,
|
||||
body: {}
|
||||
}, done);
|
||||
}, function (err) {
|
||||
console.log('complete in', hrtime(start), 'ms');
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
], function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
@ -1,72 +0,0 @@
|
||||
var async = require('async');
|
||||
var fs = require('fs');
|
||||
var S = require('string');
|
||||
|
||||
var restSpecDir = './src/elasticsearch/rest-api-spec/api/';
|
||||
|
||||
function fileExists(path, done) {
|
||||
fs.stat(path, function (err, stats) {
|
||||
var exists;
|
||||
|
||||
if (err) {
|
||||
if (err.message.match(/enoent/i)) {
|
||||
err = void 0;
|
||||
exists = false;
|
||||
}
|
||||
} else if (stats.isFile()) {
|
||||
exists = true;
|
||||
} else {
|
||||
err = new Error('weird stats: ' + JSON.stringify(stats));
|
||||
}
|
||||
|
||||
done(err, exists);
|
||||
});
|
||||
}
|
||||
|
||||
fs.readdir(restSpecDir, function (err, files) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
async.forEachSeries(files, function (fileName, done) {
|
||||
var apiName = S(fileName.replace(/\.json$/, '')).camelize().s;
|
||||
var filePath = './docs/_descriptions/' + apiName;
|
||||
var jadeFileExists;
|
||||
var asciiFileExists;
|
||||
|
||||
async.series([
|
||||
function (done) {
|
||||
fileExists(filePath + '.jade', function (err, exists) {
|
||||
jadeFileExists = exists;
|
||||
done(err);
|
||||
});
|
||||
},
|
||||
function (done) {
|
||||
fileExists(filePath + '.asciidoc', function (err, exists) {
|
||||
asciiFileExists = exists;
|
||||
done(err);
|
||||
});
|
||||
},
|
||||
function (done) {
|
||||
if (jadeFileExists && !asciiFileExists) {
|
||||
console.log(apiName, 'jade, no ascii');
|
||||
fs.rename(filePath + '.jade', filePath + '.asciidoc', done);
|
||||
}
|
||||
else if (!jadeFileExists && !asciiFileExists) {
|
||||
console.log(apiName, 'no jade, no ascii');
|
||||
fs.writeFile(filePath + '.asciidoc', '', done);
|
||||
}
|
||||
else if (jadeFileExists) {
|
||||
console.log(apiName, 'jade');
|
||||
fs.unlink(filePath + '.jade', done);
|
||||
}
|
||||
}
|
||||
], done);
|
||||
}, function done(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log('done');
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1,110 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z $ES_BRANCH ]; then
|
||||
echo "Missing ES_BRANCH environment var"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROOT="$PWD"
|
||||
ES_SUBMODULE="$ROOT/src/elasticsearch"
|
||||
SNAPSHOTS="$ROOT/.snapshots"
|
||||
ES_VERSION="${ES_BRANCH}_nightly"
|
||||
ES_URL="http://s3-us-west-2.amazonaws.com/build.elasticsearch.org/origin/$ES_BRANCH/nightly/JDK6/elasticsearch-latest-SNAPSHOT.zip"
|
||||
|
||||
if [ ! -z $ES_RELEASE ]; then
|
||||
ES_VERSION="v${ES_RELEASE}"
|
||||
ES_URL="https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-${ES_RELEASE}.zip"
|
||||
fi
|
||||
|
||||
ES_DIR="$SNAPSHOTS/$ES_VERSION"
|
||||
ES_BIN="$ES_DIR/bin/elasticsearch"
|
||||
|
||||
function fold {
|
||||
if [ $TRAVIS = "true" ]; then
|
||||
echo -e "travis_fold:$1"
|
||||
fi
|
||||
}
|
||||
|
||||
function check {
|
||||
RESULT=$1
|
||||
if [ "$RESULT" -gt "0" ]; then
|
||||
echo "non-zero exit code: $RESULT"
|
||||
exit $RESULT
|
||||
fi
|
||||
}
|
||||
|
||||
fold "start:setup_es"
|
||||
echo "Setting up elasticsearch"
|
||||
|
||||
echo "Killing existsing java processes"
|
||||
killall java 2>/dev/null
|
||||
|
||||
if [ ! -d "$SNAPSHOTS" ]; then
|
||||
mkdir $SNAPSHOTS
|
||||
fi
|
||||
|
||||
cd $SNAPSHOTS
|
||||
|
||||
if [ ! -d "$ES_DIR" ]; then
|
||||
echo "Downloading Elasticsearch $ES_VERSION to $ES_DIR"
|
||||
|
||||
|
||||
curl -O $ES_URL \
|
||||
&& unzip elasticsearch-*.zip
|
||||
check $?
|
||||
|
||||
rm elasticsearch-*.zip
|
||||
check $?
|
||||
|
||||
mv elasticsearch-*/ $ES_DIR
|
||||
check $?
|
||||
fi
|
||||
|
||||
cd $ROOT
|
||||
|
||||
if [ ! -x "$ES_BIN" ]; then
|
||||
echo "Unable to find elasticsearch executable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$ES_BRANCH" = "0.90" ]; then
|
||||
echo "Starting Elasticsearch $ES_VERSION"
|
||||
$ES_BIN \
|
||||
-Des.network.host=localhost \
|
||||
-Des.discovery.zen.ping.multicast.enabled=false \
|
||||
-Des.discovery.zen.ping_timeout=1
|
||||
check $?
|
||||
else
|
||||
echo "Starting Elasticsearch $ES_VERSION as a deamon"
|
||||
$ES_BIN -d \
|
||||
-Des.network.host=localhost \
|
||||
-Des.discovery.zen.ping.multicast.enabled=false \
|
||||
-Des.discovery.zen.ping_timeout=1
|
||||
check $?
|
||||
fi
|
||||
fold "end:setup_es"
|
||||
|
||||
|
||||
if [ ! -x "`which grunt`" ]; then
|
||||
fold "start:install_grunt"
|
||||
echo "installing grunt-cli"
|
||||
npm install -g grunt-cli
|
||||
check $?
|
||||
fold "end:install_grunt"
|
||||
fi
|
||||
|
||||
if [ -z "$NO_UNIT" ]; then
|
||||
grunt jshint mochacov:unit
|
||||
check $?
|
||||
fi
|
||||
|
||||
if [ -z "$NO_INTEGRATION" ]; then
|
||||
grunt --es_branch="=$ES_BRANCH" run:generate_yaml_tests mochacov:integration
|
||||
check $?
|
||||
fi
|
||||
|
||||
if [ -n "$COVERAGE" ]; then
|
||||
grunt mochacov:ship_coverage
|
||||
fi
|
||||
|
||||
killall java 2>/dev/null
|
||||
17
test/angular_build_unit_tests.html
Normal file
17
test/angular_build_unit_tests.html
Normal file
@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="expect.js"></script>
|
||||
<script src="mocha.js"></script>
|
||||
<script>mocha.setup('bdd');</script>
|
||||
<script>mocha.checkLeaks();</script>
|
||||
<script src="angular.js"></script>
|
||||
<script src="angular_build.js"></script>
|
||||
<script src="begin!"></script>
|
||||
</body>
|
||||
</html>
|
||||
17
test/browser_build_unit_tests.html
Normal file
17
test/browser_build_unit_tests.html
Normal file
@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="expect.js"></script>
|
||||
<script src="mocha.js"></script>
|
||||
<script>mocha.setup('bdd');</script>
|
||||
<script>mocha.checkLeaks();</script>
|
||||
<script src="angular.js"></script>
|
||||
<script src="angular_build.js"></script>
|
||||
<script src="begin!"></script>
|
||||
</body>
|
||||
</html>
|
||||
17
test/jquery_build_unit_tests.html
Normal file
17
test/jquery_build_unit_tests.html
Normal file
@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="expect.js"></script>
|
||||
<script src="mocha.js"></script>
|
||||
<script>mocha.setup('bdd');</script>
|
||||
<script>mocha.checkLeaks();</script>
|
||||
<script src="angular.js"></script>
|
||||
<script src="angular_build.js"></script>
|
||||
<script src="begin!"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,6 +1,6 @@
|
||||
module.exports = function (makeLogger) {
|
||||
var expect = require('expect.js');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
var fs = require('fs');
|
||||
var once = require('events').EventEmitter.prototype.once;
|
||||
var _ = require('lodash');
|
||||
|
||||
@ -6,7 +6,7 @@ var now = new Date('2013-03-01T00:00:00Z');
|
||||
var sinon = require('sinon');
|
||||
|
||||
module.exports = function (makeLogger) {
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
var parent = new Log();
|
||||
|
||||
afterEach(function () {
|
||||
|
||||
@ -5,7 +5,7 @@ describe('Logger Abstract', function () {
|
||||
var LoggerAbstract = require('../../src/lib/logger');
|
||||
|
||||
var parentLog;
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
function makeLogger(parent, levels) {
|
||||
return new LoggerAbstract(parent || parentLog, {
|
||||
|
||||
@ -5,7 +5,7 @@ var expect = require('expect.js');
|
||||
var _ = require('lodash');
|
||||
var errors = require('../../src/lib/errors');
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
describe('Connection Abstract', function () {
|
||||
var host = new Host('localhost:9200');
|
||||
|
||||
@ -6,7 +6,7 @@ var _ = require('lodash');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
function listenerCount(emitter, event) {
|
||||
if (EventEmitter.listenerCount) {
|
||||
|
||||
@ -20,7 +20,7 @@ function makeLogger(parent, levels) {
|
||||
return new ConsoleLogger(parent, config);
|
||||
}
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
describe('Console Logger', function () {
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ describe('File Logger', function () {
|
||||
var logger;
|
||||
var expect = require('expect.js');
|
||||
var fs = require('fs');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
beforeEach(function () {
|
||||
parentLog = new Log();
|
||||
|
||||
@ -17,7 +17,7 @@ describe('Http Connector', function () {
|
||||
|
||||
nock.disableNetConnect();
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
function makeStubReqMethod(prep) {
|
||||
return function (params, cb) {
|
||||
|
||||
@ -2,7 +2,7 @@ describe('JSON serializer', function () {
|
||||
var JsonSerializer = require('../../src/lib/serializers/json');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
function makeSerializer() {
|
||||
return new JsonSerializer();
|
||||
|
||||
@ -22,7 +22,7 @@ describe('Stdio Logger', function () {
|
||||
return new StdioLogger(parent, config);
|
||||
}
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
require('./generic_logger_tests')(makeLogger);
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ describe('Stream Logger', function () {
|
||||
var expect = require('expect.js');
|
||||
var parentLog;
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
beforeEach(function () {
|
||||
stub(stream, 'write');
|
||||
|
||||
@ -22,7 +22,7 @@ describe('Tracer Logger', function () {
|
||||
return new TracerLogger(parent, config);
|
||||
}
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
|
||||
require('./generic_logger_tests')(makeLogger);
|
||||
|
||||
@ -7,7 +7,7 @@ var sinon = require('sinon');
|
||||
var expect = require('expect.js');
|
||||
var _ = require('lodash');
|
||||
var nodeList = require('../fixtures/short_node_list.json');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
/**
|
||||
* Allows the tests call #request() without it doing anything past trying to select
|
||||
|
||||
@ -8,7 +8,7 @@ var sinon = require('sinon');
|
||||
var nock = require('../mocks/server.js');
|
||||
var _ = require('lodash');
|
||||
var nodeList = require('../fixtures/short_node_list.json');
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
/**
|
||||
* Allows the tests call #request() without it doing anything past trying to select
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
var _ = require('../../src/lib/utils');
|
||||
var expect = require('expect.js');
|
||||
|
||||
var stub = require('./auto_release_stub').make();
|
||||
var stub = require('../utils/auto_release_stub').make();
|
||||
|
||||
describe('Utils', function () {
|
||||
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="jquery.js"></script>
|
||||
<script src="expect.js"></script>
|
||||
<script src="mocha.js"></script>
|
||||
<script>mocha.setup('bdd')</script>
|
||||
<script src="test.array.js"></script>
|
||||
<script src="test.object.js"></script>
|
||||
<script src="test.xhr.js"></script>
|
||||
<script>
|
||||
mocha.checkLeaks();
|
||||
mocha.globals(['jQuery']);
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
20588
test/utils/angular.js
vendored
Normal file
20588
test/utils/angular.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9789
test/utils/jquery.js
vendored
Normal file
9789
test/utils/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5598
test/utils/mocha.js
5598
test/utils/mocha.js
File diff suppressed because it is too large
Load Diff
89
test/utils/server/index.js
Normal file
89
test/utils/server/index.js
Normal file
@ -0,0 +1,89 @@
|
||||
var express = require('express');
|
||||
var http = require('http');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var root = path.join(__dirname, '../../..');
|
||||
var glob = require('glob');
|
||||
var browserify = require('browserify');
|
||||
|
||||
var pkg = require(root + '/package.json');
|
||||
|
||||
var defaultFiles = _.transform(pkg.testling.files, function (files, pattern) {
|
||||
[].push.apply(files, _.map(glob.sync(pattern), function (filename) {
|
||||
console.log('resolving', filename);
|
||||
return path.resolve(root, filename);
|
||||
}));
|
||||
}, []);
|
||||
|
||||
var aliasify = require('aliasify').configure({
|
||||
aliases: pkg.browser,
|
||||
excludeExtensions: 'json',
|
||||
// verbose: false,
|
||||
configDir: root
|
||||
});
|
||||
|
||||
function browserBuild(name) {
|
||||
return function (req, res, next) {
|
||||
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
|
||||
var b = browserify(_.union(defaultFiles, [
|
||||
path.resolve(root, 'test/unit/browser_test_' + name + '_build.js')
|
||||
]));
|
||||
b.transform(aliasify);
|
||||
b.bundle({
|
||||
insertGlobals: true
|
||||
}).pipe(res);
|
||||
};
|
||||
}
|
||||
|
||||
function sendFile(file) {
|
||||
return function (req, res, next) {
|
||||
res.sendfile(file);
|
||||
};
|
||||
}
|
||||
|
||||
var app = express();
|
||||
|
||||
app
|
||||
.use(express.logger('dev'))
|
||||
.use(app.router)
|
||||
// runners
|
||||
.get('/browser.html', sendFile(root + '/test/angular_build_unit_tests.html'))
|
||||
.get('/jquery.html', sendFile(root + '/test/angular_build_unit_tests.html'))
|
||||
.get('/angular.html', sendFile(root + '/test/angular_build_unit_tests.html'))
|
||||
|
||||
// support
|
||||
.get('/expect.js', sendFile(root + '/node_modules/expect.js/expect.js'))
|
||||
.get('/mocha.css', sendFile(root + '/node_modules/mocha/mocha.css'))
|
||||
.get('/mocha.js', sendFile(root + '/node_modules/mocha/mocha.js'))
|
||||
|
||||
// libs
|
||||
.get('/angular.js', sendFile(root + '/test/utils/angular.js'))
|
||||
.get('/jquery.js', sendFile(root + '/test/utils/jquery.js'))
|
||||
|
||||
// bundles
|
||||
.get('/angular_build.js', browserBuild('angular'))
|
||||
.get('/jquery_build.js', browserBuild('jquery'))
|
||||
.get('/browser_build.js', browserBuild('browser'))
|
||||
|
||||
// stupid
|
||||
.get('/begin!', function (req, res) {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.send([
|
||||
'mocha.run().on(\'end\', function () {',
|
||||
' var stats = window.completeTestStats = {};',
|
||||
' for (var key in this.stats) {',
|
||||
' if (this.stats.hasOwnProperty(key)) {',
|
||||
' stats[key] = this.stats[key];',
|
||||
' }',
|
||||
' }',
|
||||
' console && console.dir && console.dir(window.completeTestStats);',
|
||||
'});'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
http.createServer(app).listen(8000, function () {
|
||||
console.log('listening on port 8000');
|
||||
});
|
||||
Reference in New Issue
Block a user