Improve rtcbot to load all test files at start and allow them to registerTests
via: registerBotTest. After loading all tests main.js starts running the
requested one on the command arguments.
R=houssainy@google.com
Review URL: https://webrtc-codereview.appspot.com/29779004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7461 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/tools/rtcbot/README b/webrtc/tools/rtcbot/README
index 72f9f63..bfa981c 100644
--- a/webrtc/tools/rtcbot/README
+++ b/webrtc/tools/rtcbot/README
@@ -17,7 +17,10 @@
== How to run the test ==
$ cd trunk/webrtc/tool/rtcbot
$ npm install express browserify ws websocket-stream dnode
- $ node test.js <test_file_path>
+ $ node main.js "<test_name>"
+
+== How can I see the list of available tests? ==
+ $ node main.js
== Example on how to install nodejs ==
$ cd /work/tools/
@@ -30,7 +33,7 @@
- "chrome": chrome on host machine.
- "android-chrome": chrome on android device. Details in "Android" Section.
- * Bot type is specified for each spawned bot in the test file.
+ * Bot type is specified directly by the test.
== Android ==
Before running test with Android one MUST forward the device port 8080 to the
diff --git a/webrtc/tools/rtcbot/main.js b/webrtc/tools/rtcbot/main.js
new file mode 100644
index 0000000..665f6e8
--- /dev/null
+++ b/webrtc/tools/rtcbot/main.js
@@ -0,0 +1,102 @@
+// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+//
+// This script loads all the test/* files into a very small context that
+// only exposes a minimal set of functions that allows to register tests.
+//
+// Once all files are loaded it runs the specific test on the command line.
+// If no arguments are given it lists all the registered tests.
+//
+// Note: the small context where the scripts are loaded is intended to keep
+// nodejs-isms away from the test code and isolate implementation details away
+// from them.
+var fs = require('fs');
+var vm = require('vm');
+var Test = require('./test.js');
+
+var testSuites = {};
+
+function registerTest(name, func) {
+ testSuites[name] = func;
+}
+
+function registerBotTest(name, func, bots) {
+ registerTest(name, bootstrap);
+
+ function bootstrap(test) {
+ var callbacks = [];
+ for (var i = 0; i != bots.length; ++i)
+ callbacks.push(test.spawnBot.bind(test, "", bots[i]));
+
+ test.wait(callbacks, func.bind(test, test));
+ }
+}
+
+function loadTestFile(filename, doneCallback) {
+ var loadTestContext = {
+ setTimeout: setTimeout,
+ registerTest: registerTest,
+ registerBotTest: registerBotTest
+ };
+ var script = vm.createScript(fs.readFileSync(filename), filename);
+ script.runInNewContext(loadTestContext);
+ doneCallback();
+}
+
+function iterateOverTestFiles(foreachCallback, doneCallback) {
+ fs.readdir('test', function (error, list) {
+ function iterateNextFile() {
+ if (list.length === 0) {
+ doneCallback();
+ } else {
+ var filename = list.pop();
+ if (filename[0] === '.' || filename.slice(-3) !== '.js') {
+ // Skip hidden and non .js files on that directory.
+ iterateNextFile();
+ } else {
+ foreachCallback('test/' + filename, iterateNextFile);
+ }
+ }
+ }
+
+ if (error !== null) {
+ throw error;
+ }
+ iterateNextFile();
+ });
+}
+
+function runTest(testname) {
+ if (testname in testSuites) {
+ console.log("Running test: " + testname);
+ var test = new Test();
+ testSuites[testname](test);
+ } else {
+ console.log("Unknown test: " + testname);
+ }
+}
+
+function printUsage() {
+ console.log('Run as:\n $ '
+ + process.argv[0] + ' ' + process.argv[1]
+ + ' <testname>');
+ console.log('These are the existent ones:');
+ for (var testname in testSuites)
+ console.log(' ' + testname);
+}
+
+function main() {
+ // TODO(andresp): support multiple tests.
+ var testList = process.argv.slice(2);
+ if (testList.length === 1)
+ runTest(testList[0]);
+ else
+ printUsage();
+}
+
+iterateOverTestFiles(loadTestFile, main);
diff --git a/webrtc/tools/rtcbot/test.js b/webrtc/tools/rtcbot/test.js
index e117398..abf0e17 100644
--- a/webrtc/tools/rtcbot/test.js
+++ b/webrtc/tools/rtcbot/test.js
@@ -6,14 +6,9 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
-// This script loads the test file in the virtual machine and runs it in a
-// context that only exposes a test variable with methods for testing and to
-// spawn bots.
-//
-// Note: an important part of this script is to keep nodejs-isms away from test
-// code and isolate it from implementation details.
+// Provides a Test class that exposes api to the tests.
+// Read test.prototype to see what methods are exposed.
var fs = require('fs');
-var vm = require('vm');
var BotManager = require('./botmanager.js');
function Test() {
@@ -134,13 +129,6 @@
doneCallback);
}
},
-}
+};
-function runTest(testfile) {
- console.log("Running test: " + testfile);
- var script = vm.createScript(fs.readFileSync(testfile), testfile);
- script.runInNewContext({ test: new Test(), setInterval: setInterval,
- setTimeout: setTimeout });
-}
-
-runTest(process.argv[2]);
+module.exports = Test;
diff --git a/webrtc/tools/rtcbot/test/ping_pong.js b/webrtc/tools/rtcbot/test/ping_pong.js
index feee3bc..1d9886e 100644
--- a/webrtc/tools/rtcbot/test/ping_pong.js
+++ b/webrtc/tools/rtcbot/test/ping_pong.js
@@ -6,8 +6,9 @@
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
-function testPingPong(bot) {
- test.log('bot:alice > Sending Ping to bot');
+function testPingPong(test, bot) {
+ test.assert(typeof bot.ping === 'function', 'Bot does not exposes ping.');
+
bot.ping(gotAnswer);
function gotAnswer(answer) {
@@ -16,4 +17,4 @@
}
}
-test.spawnBot("alice", "chrome", testPingPong);
+registerBotTest('testPingPong/chrome', testPingPong, ['chrome']);
diff --git a/webrtc/tools/rtcbot/test/simple_offer_answer.js b/webrtc/tools/rtcbot/test/simple_offer_answer.js
index e052598..43553f0 100644
--- a/webrtc/tools/rtcbot/test/simple_offer_answer.js
+++ b/webrtc/tools/rtcbot/test/simple_offer_answer.js
@@ -10,17 +10,12 @@
//
// Note: This test does not performs ice candidate exchange and
// does not verifies that media can flow between the peers.
-function testOfferAnswer(peer1, peer2) {
- test.wait([
- createPeerConnection.bind(peer1),
- createPeerConnection.bind(peer2) ],
- establishCall);
+function testOfferAnswer(test, bot1, bot2) {
+ test.wait( [ bot1.createPeerConnection.bind(bot1, null),
+ bot2.createPeerConnection.bind(bot2, null) ],
+ run);
- function createPeerConnection(done) {
- this.createPeerConnection(null, done, test.fail);
- }
-
- function establishCall(pc1, pc2) {
+ function run(pc1, pc2) {
test.log("Establishing call.");
pc1.createOffer(gotOffer);
@@ -38,17 +33,16 @@
pc2.setLocalDescription(answer, expectedCall, test.fail);
pc1.setRemoteDescription(answer, expectedCall, test.fail);
}
+
+ // TODO(andresp): Implement utilities in test to write expectations
+ // that certain methods must be called.
+ var expectedCalls = 0;
+ function expectedCall() {
+ if (++expectedCalls == 6)
+ test.done();
+ }
}
}
-// TODO(andresp): Implement utilities in test to write expectations that certain
-// methods must be called.
-var expectedCalls = 0;
-function expectedCall() {
- if (++expectedCalls == 6)
- test.done();
-}
-
-test.wait( [ test.spawnBot.bind(test, "alice", "chrome"),
- test.spawnBot.bind(test, "bob", "chrome") ],
- testOfferAnswer);
+registerBotTest('testOfferAnswer/chrome=>chrome',
+ testOfferAnswer, ['chrome', 'chrome']);
diff --git a/webrtc/tools/rtcbot/test/webrtc_video_streaming.js b/webrtc/tools/rtcbot/test/webrtc_video_streaming.js
index 62b7056..9142c53 100644
--- a/webrtc/tools/rtcbot/test/webrtc_video_streaming.js
+++ b/webrtc/tools/rtcbot/test/webrtc_video_streaming.js
@@ -11,11 +11,7 @@
// and then write these stats to a file.
//
// Note: the source of the video and audio stream is getUserMedia().
-//
-function testVideoStreaming(bot1, bot2) {
- var pc1 = null;
- var pc2 = null;
-
+function testOneWayVideo(test, bot1, bot2) {
var report = test.createStatisticsReport("webrtc_video_streaming");
test.wait([
@@ -29,10 +25,8 @@
}.bind(this), test.fail);
}
- function onPeerConnectionCreated(peer1, peer2) {
+ function onPeerConnectionCreated(pc1, pc2) {
test.log("RTC Peers created.");
- pc1 = peer1;
- pc2 = peer2;
pc1.addEventListener('addstream', test.fail);
pc2.addEventListener('addstream', onAddStream);
pc1.addEventListener('icecandidate', onIceCandidate.bind(pc2));
@@ -45,7 +39,7 @@
pc1.addStream(stream);
bot1.showStream(stream.id, true, true);
- createOfferAndAnswer();
+ createOfferAndAnswer(pc1, pc2);
}
}
@@ -55,18 +49,18 @@
}
function onIceCandidate(event) {
- if(event.candidate){
+ if(event.candidate) {
test.log(event.candidate.candidate);
this.addIceCandidate(event.candidate,
onAddIceCandidateSuccess, test.fail);
- };
+ }
function onAddIceCandidateSuccess() {
test.log("Candidate added successfully");
- };
+ }
}
- function createOfferAndAnswer() {
+ function createOfferAndAnswer(pc1, pc2) {
test.log("Creating offer.");
pc1.createOffer(gotOffer, test.fail);
@@ -103,6 +97,5 @@
}
}
-test.wait( [ test.spawnBot.bind(test, "alice", "chrome"),
- test.spawnBot.bind(test, "bob", "android-chrome") ],
- testVideoStreaming);
+registerBotTest('testOneWayVideo/chrome=>chrome',
+ testOneWayVideo, ['chrome', 'chrome']);