I working with Soda.js, mocha and selenium RC. I'm trying to speed up my testing and one way I was thinking is since I'm starting a new session for each test (i.e. running through closing/opening an new browser and logging into a site).
I've seen numerious incomplete posts on various forums/message boards about reusing sessions for other languages but my tests are all Javascript.
Does anyone know how I can reuse the previous browser/session once I start my tests so I dont have to start a new session in each test.
My test runner for soda looks like this.
var soda = require('soda'),
util = require('util'),
//config object - values injected by TeamCity
config = {
host: process.env['SELENIUM_HOST'] || 'localhost',
port: process.env['SELENIUM_PORT'] || 4444,
url: process.env['SELENIUM_SITE'] || 'http://google.com',
browser: process.env['SELENIUM_BROWSER'] || 'firefox'
};
describe("TEST_SITE", function(){
beforeEach(
function(done){
browser = soda.createOnPointClient(config);
// Log commands as they are fired
browser.on('command', function(cmd, args){
console.log(' \x1b[33m%s\x1b[0m: %s', cmd, args.join(', '));
});
//establish the session
browser.session(function(err){
done(err);
});
}
);
afterEach(function(done){
browser.testComplete(function(err) {
console.log('done');
if(err) throw err;
done();
});
});
describe("Areas",function(){
var tests = require('./areas');
for(var test in tests){
if(tests.hasOwnProperty(test)){
test = tests[test];
if(typeof( test ) == 'function')
test();
else if (util.isArray(test)) {
for(var i=0, l=test.length;i<l;i++){
if(typeof( test[i] ) == 'function')
test[i]();
}
}
}
}
});
});
I found my answer. I really needed to be concentrating on mocha more for my answer which was along the lines of this:
//before running the suite, create a connection to the Selenium server
before(
function(done){
browser = soda.createOnPointClient(config);
// Log commands as they are fired
browser.on('command', function(cmd, args){
console.log(' \x1b[33m%s\x1b[0m: %s', cmd, args.join(', '));
});
//establish the session
browser.session(function(err){
done(err);
});
}
);
//after each test has completed, send the browser back to the main page (hopefully cleaning our environment)
afterEach(function(done){browser.open('/',function(){
done();
});
});
//after the entire suite has completed, shut down the selenium connection
after(function(done){
browser.testComplete(function(err) {
console.log('done');
if(err) throw err;
done();
});
});
The result so far was that I'm not seeing any real performance gain by reusing the session over starting a new one. My tests still take roughly the same amount of time.
Related
I am unable to execute the sql, when using the global database connection in node.js.
I have followed the steps as in Azure documentation: https://learn.microsoft.com/en-us/azure/mysql/connect-nodejs and able to display the output on the console. But, I want to put all my Azure SQL database connection in a separate file, but the select query is not printing the output on the console.
DatabaseManager.js
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var sqlConnection = function sqlConnection() {
// Create connection to database
var config =
{
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options:
{
database: 'mydatabase',
encrypt: true
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err)
{
console.log(err)
}
else
{
console.log('CONNECTED TO DATABASE');
}
}
);
}
module.exports = sqlConnection;
app.js
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var azure = require('azure-storage');
var dbconnection = require('./DatabaseManager');
bot.dialog('profileDialog',
(session) => {
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Reading rows from the Table...');
dbconnection("select FNAME from StudentProfile where ID=1"),
function (err, result, fields) {
if (err) throw err;
console.log(result);
}
session.endDialog();
}
Console Output:
Reading rows from the Table...
CONNECTED TO DATABASE
I was expecting the output of FNAME, but nothing is printing on the console. Is there anything, I am missing?
Thank you.
There's a couple of problems here. First off, you should only ever import a module once per file. This is just a performance consideration and won't actually break your code.
Next, pay attention to what you're exporting from your DatabaseManager module. Right now, you're exporting a function that creates the connection and then doesn't do anything with it. We can fix this by using a pattern called a "callback" which lets us provide a function that will then be called with the connection as an argument.
I added a ton of comments to the code explaining things. This code won't run as-is - there's a couple places where I have "do this or this". You'll have to choose one.
var Tedious = require('tedious'); // Only require a library once per file
var Connection = Tedious.Connection;
var Request = Tedious.Request;
// Or using the object spread operator
var { Connection, Request } = require('tedious');
// You called this `sqlConnection`. I'm going to use a verb since it's a
// function and not a variable containing the connection. I'm also going
// to change the declaration syntax to be clearer.
function connect(cb) { // cb is short for callback. It should be a function.
var config = {
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options: {
database: 'mydatabase',
encrypt: true
}
}; // Put a semi-colon on your variable assignments
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err) {
console.log(err);
return; // Stop executing the function if it failed
}
// We don't need an "else" because of the return statement above
console.log('CONNECTED TO DATABASE');
// We have a connection, now let's do something with it. Call the
// callback and pass it the connection.
cb(connection);
});
}
module.exports = connect; // This exports a function that creates the connection
Then back in your main file, you can use it like so.
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require('botbuilder-azure');
var azure = require('azure-storage');
var connect = require('./DatabaseManager'); // renamed to be a verb since it's a function.
bot.dialog('profileDialog', (session) => { // Hey, this is a callback too!
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Creating a connection');
connect((connection) => {
// or with the traditional function notation
connect(function(connection) {
console.log('Reading rows from the Table...');
// Execute your queries here using your connection. This code is
// taken from
// https://github.com/tediousjs/tedious/blob/master/examples/minimal.js
request = new Request("select FNAME from StudentProfile where ID=1", function(err, rowCount) { // Look another callback!
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) { // Iterate through the rows using a callback
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
connection.execSql(request);
});
I am using node.js and selenium to build automated tests. So, when starting the script in one terminal, I use Commander to open another terminal and start selenium when I launch my automated tests. I do that like this when I want to do the testing with Safari:
if(myArgs.indexOf("LOCAL_SAF") != -1)
{ console.log('Starting selenium');
/* use Commander to open a shell script which opens a terminal and starts Selenium */
exec('open -a Terminal.app startSeleniumForSafari.sh',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
wait(2500);
console.log('Selenium should be started');
/* get the selenium webdriver executable for safari*/
safari = require('selenium-webdriver/safari');
browserUnderTest = new webdriver.Builder()
.forBrowser('safari')
.usingServer('http://localhost:4444/wd/hub')
.build();
}
/*
THIS IS NOT MY CODE. This came from
https://stackoverflow.com/questions/14226803/javascript-wait-5-seconds-before-executing-next-line
and was simple enough to understand, and suited my purposes.
*/
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
Rather then have a wait time and then print to the console that 'Selenium should be started', I'd like to somehow detect that it has indeed started, or if there is an error.
Is there a way to check the current status of the selenium server if it was launched in another terminal?
I know that calling http://localhost:4444/wd/hub/status will result in a response with JSON like {"state":"success","sessionId":null,"hCode":1982803459,"value":{"build":{"version":"2.52.0","revision":"4c2593c","time":"2016-02-11 19:06:42"},"os":{"name":"Mac OS X","arch":"x86_64","version":"10.12.6"},"java":{"version":"1.8.0_121"}},"class":"org.openqa.selenium.remote.Response","status":0}
But I know neither how to get that, nor what to do with it once gotten.
I do not have experience with Selenium or Commander so there might be a better solution, but this may be of help or point someone in the right direction.
For one, you should be able to make a cURL request, like: curl http://localhost:4444/wd/hub/status
It is possible to send messages back and forth between processes, as described here.
You could play around with this premise, like so:
From the Parent:
const child_process = require('child_process');
let options = {
stdio: [process.stdin, process.stdout, process.stderr, 'pipe', 'pipe']
};
let child = child_process.spawn('command', ['parameters', 'here'], options);
child.stdio[3].write('A message to the new terminal');
child.stdio[4].pipe(process.stdout);
From the child process:
const fs = require('fs');
fs.createWriteStream(null, {fd: 4}).write('A message from new terminal.');
--
Also, this npm package seems like it might solve this problem for you:
https://www.npmjs.com/package/wd
Thought I do like Adam Patterson's recommendation, I had already started down a particular path and wanted to see it through. I may try Here is how I solved the problem, for better or for worse:
if(myArgs.indexOf("LOCAL_SAF") != -1)
{
startSelenium('open -a Terminal.app startSeleniumForSafari.sh');
/* get the selenium webdriver executable for safari*/
safari = require('selenium-webdriver/safari');
browserUnderTest = new webdriver.Builder()
.forBrowser('safari')
.usingServer('http://localhost:4444/wd/hub')
.build();
}
function startSelenium(terminalCommand){
console.log('Starting selenium');
var seleniumRunning = getSeleniumStatus();
if (seleniumRunning != 'success' ) {
/* use Commander to open a shell script which opens a terminal and starts Selenium */
exec(terminalCommand,
function (error, stdout, stderr) {
// console.log('stdout: ' + stdout);
// console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
}
wait(2500);
}
/*
THIS IS NOT MY CODE.
I needed a way, using javascript to just wait while Selenium starts up. This came from
https://stackoverflow.com/questions/14226803/javascript-wait-5-seconds-before-executing-next-line
was simple enough to understand, and suited my purposes.
*/
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
/*
THIS IS ALSO NOT MY CODE. I made some slight modifications to...
https://stackoverflow.com/questions/5643321/how-to-make-remote-rest-call-inside-node-js-any-curl
*/
function getSeleniumStatus(){
http.get('http://localhost:4444/wd/hub/status', function (res) {
var json = '';
res.on('data', function (chunk) {
json += chunk;
});
res.on('end', function () {
if (res.statusCode === 200) {
try {
var data = JSON.parse(json);
// data is available here:
// console.log(data.state);
if (data.state === 'success'){
console.log( data.state + "! Selenium is running.")
}
else {
console.log( data.state + " problem starting selenium.")
}
// return it
return data.state;
} catch (e) {
console.log('Error parsing JSON!');
}
} else {
console.log('Status:', res.statusCode);
}
});
}).on('error', function (err) {
console.log('Error:', err);
});
}
/*
END https://stackoverflow.com/questions/14226803/javascript-wait-5-seconds-before-executing-next-line
- & -
https://stackoverflow.com/questions/5643321/how-to-make-remote-rest-call-inside-node-js-any-curl
*/
I've read through a number of SO questions about nodejs running out of memory, but I haven't seen anything that sounds similar to my situation.
I'm trying to process about 20GBs of data across 250 csv files (so ~80MBs/file). Launch the node script with --max-old-space-size=8192 on a server with 90GB of free memory using node v5.9.1. After 9mins of processing the script quits with an out-of-memory error.
I'm new to Node programming, but I thought I wrote the script to process data one line at a time and not to keep anything in memory. Yet it seems some object references are being held on to by something, so the script is leaking memory. Here's the full script:
var fs = require('fs');
var readline = require('readline');
var mongoose = require('mongoose');
mongoose.connect('mongodb://buzzard/xtra');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
var DeviceSchema = mongoose.Schema({
_id: String,
serial: String
});
var Device = mongoose.model('Device', DeviceSchema, 'devices');
function processLine(line) {
var serial = line.split(',')[8];
Device({
_id: serial,
serial: serial
}).save(function (err) {
if (err) return console.error(err);
});
}
function processFile(baseDir, fileName) {
if(!fileName.startsWith('qcx3'))
return;
var fullPath = `${baseDir}/${fileName}`;
var lineReader = readline.createInterface({
input: fs.createReadStream(fullPath)
});
lineReader.on('line', processLine);
}
function findFiles(rootDir) {
fs.readdir(rootDir, function (error, files) {
if (error) {
console.log(`Error: ${error}` );
return
}
files.forEach(function (file) {
if(file.startsWith('.'))
return;
var fullPath = `${rootDir}/${file}`;
fs.stat(fullPath, function(error, stat) {
if (error) {
console.log(`Error: ${error}` );
return;
}
if(stat.isDirectory())
dir(fullPath);
else
processFile(rootDir, file);
});
});
})
}
findFiles('c://temp/logs/compress');
I also noticed that when I run the script on a much smaller test set that it can completely finish processing, the script doesn't exit at the end. Just keeps hanging there until I ctrl+c it. Could this be somehow related?
What am I doing wrong?
The script is not exiting cause you have an open connection to mongoose, after all the files has been processed you should close the connection and the script will finish.
You have the right Idea of using streams but i think you missed something on the way, I suggest you the following article to update the streamInterface, and events. https://coderwall.com/p/ohjerg/read-large-text-files-in-nodejs
An other source of problem could be the mongodb, it seems you make a lot of inserts, it could be related with the max i/o of mongodb that exhaust the memory.
I just started nodejs development. I am testing mongodb driver but repeatedly getting assertEquals has no method.
code from sourceRepo
var client = new Db('test', new Server("127.0.0.1", 27017, {})),
test = function (err, collection) {
collection.insert({a:2}, function(err, docs) {
collection.count(function(err, count) {
test.assertEquals(1, count);
});
// Locate all the entries using find
collection.find().toArray(function(err, results) {
test.assertEquals(1, results.length);
test.assertTrue(results[0].a === 2);
// Let's close the db
client.close();
});
});
};
client.open(function(err, p_client) {
client.collection('test_insert', test);
});
Error
has no method 'assertEquals'
How to reolve it?
You can use Node's Assert for this (where it is called equal rather than equal*s*):
var assert = require('assert');
// ...
assert.equal(count, 1);
// ...
However, for Unit tests or something similar you should consider using some testing framework. eg. Jasmine for Node, which is very popular.
assert.equal is deprecated: use assert.strictEqual() instead.
assert.equal(1, '1');
// OK, 1 == '1'
assert.strictEqual(1, '1');
// FAIL, 1 === '1'
Docs: https://nodejs.org/api/assert.html#assert_assert_equal_actual_expected_message
I am writing small node.js server for helping maintaining build machines. It's basically for testers to be able to drop db or restart server remotely. I have some issues with pg connections. Can anybody have an idea why it is not being closed after first request?
var client = new pg.Client(conString);
var server = http.createServer(function (req, res) {
var url = parse(req.url);
if (url.pathname =='/'){
(...)
}else{
var slash_index = url.pathname.indexOf('/',1);
var command = url.pathname.slice(1,slash_index);
if (command =='restart'){
res.write('restarting server please wait');
} else if (command == 'drop-db'){
console.log('drop-db');
client.connect();
console.log('connect');
var query = client.query("select datname from pg_database;", function(err, result) {
if (err) throw err;
console.log('callback');
});
query.on('end', function() {
console.log('close');
client.end();
});
} else{
res.write('unknown command : '+ command);
}
res.write('\n');
res.end();
}
}).listen(5337);
So what I get on screen after first request is :
drop-db
connect
callback
close
great but after next request I get only
drop-db
connect
after next one I already get an pg error
what do I do wrong?
Edit : No errors after second commit . Error after third :
events.js:48
throw arguments[1]; // Unhandled 'error' event
^
error: invalid frontend message type 0
at [object Object].<anonymous> (/home/wonglik/workspace/server.js/node_modules/pg/lib/connection.js:412:11)
at [object Object].parseMessage (/home/wonglik/workspace/server.js/node_modules/pg/lib/connection.js:287:17)
at Socket.<anonymous> (/home/wonglik/workspace/server.js/node_modules/pg/lib/connection.js:45:22)
at Socket.emit (events.js:88:20)
at TCP.onread (net.js:347:14)
I think it is related to opening new connection while old is still on.
Edit 2 :
I've checked postgres logs :
after second request :
2012-03-13 09:23:22 EET LOG: invalid length of startup packet
after third request :
2012-03-13 09:24:48 EET FATAL: invalid frontend message type 0
It looks like client (pg.Client) is declared outside the scope of a request, this is probably your issue. It's hard to tell from the code snippet, but it looks like you might have issues with scoping and how async callback control flow works in general, e.g. calling res.end() while callbacks are still in the IO queue. This is totally legal with node, just not sure that is your intent.
It is preferred to use pg.connect which returns a client. see https://github.com/brianc/node-postgres/wiki/pg
var pg = require('pg');
var server = http.createServer(function (req, res) {
var url = parse(req.url);
if (url.pathname =='/'){
(...)
}else{
var slash_index = url.pathname.indexOf('/',1);
var command = url.pathname.slice(1,slash_index);
if (command =='restart'){
res.write('restarting server please wait');
} else if (command == 'drop-db'){
console.log('drop-db');
pg.connect(conString, function(err, client) {
console.log('connect');
var query = client.query("select datname from pg_database;", function(err, result) {
if (err) throw err;
console.log('callback');
});
query.on('end', function() {
console.log('close');
// client.end(); -- not needed, client will return to the pool on drain
});
});
} else{
res.write('unknown command : '+ command);
}
// these shouldn't be here either if you plan to write to res from within the pg
// callback
res.write('\n');
res.end();
}
}).listen(5337);
I was getting this error, similar to you, and it was that the connection wasn't closed. When you attempt to (re)connect via an already open connection, things go boom. I would suggest that you use the direct connection stuff, since you don't seem to need the pooling code - might make it easier to trap the problem. (Though, given that I've resurrected an older post, I suspect that you probably already fixed this.)