├── README.md
├── backend
└── nodejute
│ ├── LICENSE
│ ├── README.md
│ ├── examples
│ ├── README.md
│ ├── clientSide
│ │ ├── testToolbar.html
│ │ ├── testToolbar.js
│ │ └── toolbar.js
│ ├── integration
│ │ └── testYahoo.js
│ └── serverSide
│ │ ├── mySum.js
│ │ ├── npm-debug.log
│ │ └── testMySum.js
│ ├── getConfig.js
│ ├── jute
│ ├── actions.js
│ ├── actions
│ │ ├── clearResults.js
│ │ ├── clearTests.js
│ │ ├── common.js
│ │ ├── getTest.js
│ │ ├── heartBeat.js
│ │ ├── message.js
│ │ ├── pop.js
│ │ ├── prune.js
│ │ ├── runTest.js
│ │ ├── startPhantomjs.js
│ │ ├── startSelenium.js
│ │ ├── startSelenium2.js
│ │ ├── status.js
│ │ ├── testReport.js
│ │ └── yuitest-coverage-report.jar
│ ├── configure.js
│ ├── daemon.js
│ ├── jute_docs
│ │ ├── capture.html
│ │ ├── jute.js
│ │ ├── jute_client.js
│ │ └── run_tests.html
│ ├── phantomJUTE.js
│ ├── server.js
│ └── yuitest-coverage.jar
│ ├── jute_backend.js
│ ├── jute_jasmine.js
│ ├── jute_v8.js
│ ├── package.json
│ ├── submit_test.js
│ ├── test
│ ├── getConfig
│ │ └── testGetConfig.js
│ ├── jute
│ │ ├── actions
│ │ │ ├── clearResults
│ │ │ │ └── testClearResults.js
│ │ │ ├── clearTests
│ │ │ │ └── testClearTests.js
│ │ │ ├── common
│ │ │ │ └── testCommon.js
│ │ │ ├── getTest
│ │ │ │ └── testGetTest.js
│ │ │ ├── heartBeat
│ │ │ │ └── testHeartBeat.js
│ │ │ ├── pop
│ │ │ │ └── testPop.js
│ │ │ └── prune
│ │ │ │ └── testPrune.js
│ │ └── configure
│ │ │ └── testConfigure.js
│ ├── jute_backend
│ │ └── testBackend.js
│ └── mock
│ │ ├── hub.js
│ │ └── req.js
│ └── testV8Script.js
└── js
├── README
└── jute.js
/backend/nodejute/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011, Yahoo! Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use of this software in source and binary forms,
5 | with or without modification, are permitted provided that the following
6 | conditions are met:
7 |
8 | * Redistributions of source code must retain the above
9 | copyright notice, this list of conditions and the
10 | following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above
13 | copyright notice, this list of conditions and the
14 | following disclaimer in the documentation and/or other
15 | materials provided with the distribution.
16 |
17 | * Neither the name of Yahoo! Inc. nor the names of its
18 | contributors may be used to endorse or promote products
19 | derived from this software without specific prior
20 | written permission of Yahoo! Inc.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
34 |
--------------------------------------------------------------------------------
/backend/nodejute/README.md:
--------------------------------------------------------------------------------
1 | JUTE Server and Backends
2 | ========================
3 |
4 | This is the code for the JUTE npm package - https://github.com/zzo/JUTE has the full JUTE scoop...
5 |
6 | Look in https://github.com/zzo/JUTE/ for full documentation.
7 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/README.md:
--------------------------------------------------------------------------------
1 | These 3 files show how it all fits together.
2 |
3 | testToolbar.html is the 'hub' - it loads YUI3 and the file being tested (toolbar.js) and the file with tests (testToolbar.js)
4 |
5 | toolbar.js so happens to use YUI3 in this example BUT it doesn't have to - it can use any (or none) JS Framework. Just make sure you HTML file loads whatever JS Framework you need for your tests to work.
6 |
7 | The tests themselves however MUST USE the YUI3 testing framework!! It's very nice and easy I promise you.
8 |
9 | Note in the HTML file the querystring '?coverage=1' tacked on to toolbar.js - this tells JUTE IF you want code coverage THIS is the file you want code coverage for.
10 |
11 | Also note in the HTML the 'log' div - IF you include this then you'll get a nice console while your unit tests run - it is NOT required. Just ensure IF you include this THEN add the 'yui3-skin-sam' class on your
element. No big.
12 |
13 | That's about it for the HTML file. And nothing to say about the file you are testing - that does not change.
14 |
15 | In your test JS file (testToolbar.js in this example) this is important:
16 |
17 |
18 | YUI({
19 | logInclude: { TestRunner: true },
20 | gallery: 'gallery-2011.06.22-20-13'
21 | }).use('gallery-jute', 'toolbar', function(Y) {
22 |
23 |
24 | This loads up the client-side part of JUTE AND in this case pulls in the 'toolbar' module that we're testing. Note if your original JS is NOT a YUI3 module then you do not need this!
25 |
26 | Then the 'meat' of the file - I defined a test suite named 'toolbar' - THIS NAME IS IMPORTANT!! It will be translated into a directory name in your output directory! This directory will contain all test results and code coverage information for this suite - so name it sanely!!
27 |
28 | Then I define some tests and finally I call:
29 |
30 |
31 | Y.Test.Runner.add(suite);
32 | Y.UnitTest.go();
33 |
34 |
35 | To kick the whole thing off.
36 |
37 | You can/should load up this HTML directly into your browser and your tests will run indendpendenly of JUTE.
38 |
39 | When you are ready to run within JUTE either run 'jute_submit_test' or run it directly via JUTE's WebUI.
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/clientSide/testToolbar.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/clientSide/testToolbar.js:
--------------------------------------------------------------------------------
1 | YUI({
2 | logInclude: { TestRunner: true },
3 | }).use('test', 'toolbar', 'console', function(Y) {
4 |
5 | var suite = new Y.Test.Suite('toolbar');
6 | suite.add(new Y.Test.Case({
7 | name:'simple test',
8 | setUp: function() {
9 | this.tb = new Y.Toolbar();
10 | },
11 | testIsObject : function () {
12 | Y.log('testIsObject');
13 | Y.Assert.isObject(this.tb);
14 | },
15 | testMessage : function () {
16 | Y.log('testIsObject');
17 | Y.Assert.areEqual(this.tb.message, "I am a toolbar!");
18 | }
19 |
20 | }));
21 |
22 | Y.Test.Runner.add(suite);
23 |
24 | //initialize the console
25 | var yconsole = new Y.Console({
26 | newestOnTop: false
27 | });
28 |
29 | yconsole.render('#log');
30 | Y.Test.Runner.run();
31 | });
32 |
33 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/clientSide/toolbar.js:
--------------------------------------------------------------------------------
1 | YUI().add('toolbar', function(Y) {
2 | Y.Toolbar = function Toolbar() {
3 | this.message = "I am a toolbar!";
4 | function hidden(testme) {
5 | var ret = testme + ' TESTED';
6 | return ret;
7 | }
8 | };
9 |
10 | Y.Toolbar.prototype = {
11 | zop: function() {
12 | this.zop = 'ZOP';
13 | }
14 | };
15 |
16 | function testme(y) {
17 | return y * 55;
18 | }
19 |
20 | }, '1.0.0' ,{requires:['attribute', 'event-custom-base', 'common-utils']});
21 |
22 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/integration/testYahoo.js:
--------------------------------------------------------------------------------
1 | //var YUI = require("yui3").YUI;
2 | YUI({
3 | logInclude: { TestRunner: true },
4 | }).use('test', function(Y) {
5 |
6 | var suite = new Y.Test.Suite('Yahoo'),
7 | soda = require('soda');
8 | browser = soda.createClient({
9 | url: 'http://yahoo.com',
10 | host: '99-184-251-18.lightspeed.sndgca.sbcglobal.net',
11 | browser: '*firefox'
12 | });
13 |
14 | suite.add(new Y.Test.Case({
15 | name:'Yahoo Search',
16 | testSearch: function() {
17 | var test = this;
18 |
19 | /*
20 | Y.log('running test search: ' + browser);
21 | Y.log('running test search: ' + browser.session);
22 | browser.session(function(err, sid) {
23 | Y.log('sess: ' + err);
24 | Y.log('sess sid: ' + sid);
25 | Y.log(browser.open);
26 | browser.open('/', function(err) {
27 | Y.log('open: ' + err);
28 | Y.log(browser.waitForPageToLoad);
29 | browser.waitForPageToLoad(10000, function(err) {
30 | Y.log('wait: ' + err);
31 | browser.testComplete(function(err) {
32 | Y.log('complete: ' + err);
33 | test.resume(function() {
34 | Y.log('resume: ' + err);
35 | Y.Assert.isNull(err);
36 | });
37 | });
38 | });
39 | });
40 | });
41 | */
42 | browser.
43 | chain.
44 | session().
45 | open('/').
46 | waitForPageToLoad(600000).
47 | typeKeys('name=p', 'ZZO Associates').
48 | submit('name=sf1').
49 | waitForPageToLoad(600000).
50 | getText('id=cquery', function(val) {
51 | console.log('TEXT: ' + val);
52 | }).
53 | verifyText('id=cquery', 'We have included zoo associates results - Show only ZZO Associates', function(error) {
54 | if (error) {
55 | console.log('TEST FAILED: ' + val);
56 | }
57 | }).
58 | testComplete().
59 | end(function(error) {
60 | test.resume(function() {
61 | Y.Assert.isNull(error);
62 | });
63 | });
64 |
65 | test.wait(1000000);
66 | }
67 | }));
68 |
69 | suite.add(new Y.Test.Case({
70 | name:'Yahoo Search Again',
71 | testSearch: function() {
72 | var test = this;
73 | browser.
74 | chain.
75 | open('/').
76 | waitForPageToLoad(10000).
77 | typeKeys('name=p', 'Walrun').
78 | submit('name=sf1').
79 | waitForPageToLoad(10000).
80 | getText('id=cquery', function(val) {
81 | console.log('TEXT: ' + val);
82 | }).
83 | verifyText('id=cquery', 'We have included zoo associates results - Show only ZZO Associates', function(error) {
84 | if (error) {
85 | console.log('TEST FAILED: ' + val);
86 | }
87 | }).
88 | testComplete().
89 | end(function(error) {
90 | test.resume(function() {
91 | Y.Assert.isNull(error);
92 | });
93 | });
94 |
95 | test.wait(10000000);
96 | }
97 | }));
98 |
99 | Y.Test.Runner.add(suite);
100 | Y.Test.Runner.run();
101 |
102 |
103 | });
104 |
105 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/serverSide/mySum.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mySum: function() {
3 | var result = 0, i = 0;
4 | if (typeof arguments[0] == 'object' && arguments[0].length) {
5 | for (;i < arguments[0].length; i++) {
6 | result += arguments[0][i];
7 | }
8 | } else {
9 | for (;i < arguments.length; i++) {
10 | result += arguments[i];
11 | }
12 | }
13 | return result;
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/serverSide/npm-debug.log:
--------------------------------------------------------------------------------
1 | info it worked if it ends with ok
2 | verbose cli [ 'node', '/usr/local/bin/npm', 'restart', 'jute' ]
3 | info using npm@1.0.22
4 | info using node@v0.4.5
5 | verbose config file /home/trostler/.npmrc
6 | verbose config file /usr/local/etc/npmrc
7 | ERR! Error: ENOENT, No such file or directory '/home/trostler/JUTE/backend/nodejute/node_modules/jute/package.json'
8 | ERR! Report this *entire* log at:
9 | ERR!
10 | ERR! or email it to:
11 | ERR!
12 | ERR!
13 | ERR! System Linux 2.6.38.8-2-vs2.3.0.37-rc17-blkio
14 | ERR! command "node" "/usr/local/bin/npm" "restart" "jute"
15 | ERR! cwd /home/trostler/JUTE/backend/nodejute/examples/serverSide
16 | ERR! node -v v0.4.5
17 | ERR! npm -v 1.0.22
18 | verbose exit [ 2, true ]
19 |
--------------------------------------------------------------------------------
/backend/nodejute/examples/serverSide/testMySum.js:
--------------------------------------------------------------------------------
1 | YUI({
2 | logInclude: { TestRunner: true },
3 | }).use('test', function(Y) {
4 |
5 | var suite = new Y.Test.Suite('mySum'),
6 | mySum = require('./examples/serverSide/mySum', true).mySum;
7 |
8 | suite.add(new Y.Test.Case({
9 | name:'simple sums',
10 | testTwoNumbers: function() {
11 | Y.Assert.areEqual(mySum(5, 5), 10);
12 | },
13 |
14 | testArray: function() {
15 | Y.log('this is fun');
16 | Y.Assert.areEqual(mySum([5, 5]), 10);
17 | }
18 |
19 | }));
20 |
21 | Y.Test.Runner.add(suite);
22 | Y.Test.Runner.run();
23 |
24 | });
25 |
26 |
27 |
--------------------------------------------------------------------------------
/backend/nodejute/getConfig.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 | module.exports = (function() {
37 | var fs = require('fs'), config;
38 |
39 | try {
40 | config = JSON.parse(fs.readFileSync('/tmp/jute.config', 'utf8'));
41 | } catch(e) {
42 | console.error('You must start the JUTE server: % npm start jute');
43 | }
44 |
45 | return function() { return config };
46 |
47 | })();
48 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 | module.exports = {
37 |
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var glob = require("glob")
41 | , path = require('path')
42 | ;
43 |
44 | hub.on('loadActions', loadActions);
45 |
46 | function loadActions() {
47 | var base = path.join(__dirname, 'actions');
48 | glob('*.js', { cwd: base }, function (err, actions) {
49 | // Suck in all available actions
50 | if (!err) {
51 | actions.forEach(function(action) {
52 | var act = require(path.join(base, action));
53 | act.Create && act.Create(hub, common);
54 | });
55 | hub.emit('actionsLoaded');
56 | } else {
57 | hub.emit(hub.LOG, hub.ERROR, "Error loading actions: " + err);
58 | process.exit(1);
59 | }
60 | });
61 | }
62 | }
63 | };
64 |
65 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/clearResults.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub) {
39 | var path = require('path');
40 |
41 | // Events I care about
42 | hub.addListener('action:clear_results', clearResults);
43 |
44 | function clearResults(req, res) {
45 | var exec = require('child_process').exec;
46 | try {
47 | exec("/bin/rm -rf " + hub.config.outputDir + '/*');
48 | } catch(e) {
49 | hub.emit(hub.LOG, hub.ERROR, 'Error clearing results: ' + e);
50 | }
51 | res.end('OK');
52 | }
53 | }
54 | };
55 |
56 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/clearTests.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | // Should just clear tests for THIS browser (or all tests if from cli?)
38 | module.exports = {
39 | Create: function(hub) {
40 |
41 | // Events I care about
42 | hub.addListener('action:clear_tests', clearTests);
43 |
44 | function clearTests(req, res) {
45 | hub.cache.tests_to_run = [];
46 | res.end('OK');
47 | }
48 | }
49 | };
50 |
51 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/common.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub) {
39 | var cache = hub.cache,
40 | common = {
41 | browserName: function(req) {
42 | return [req.headers['user-agent'], req.connection.remoteAddress].join('---');
43 | },
44 |
45 | makeSaneNames: function(browser) {
46 | var names = browser.split('---'),
47 | filename = names[0],
48 | ip = names[1],
49 | pkgname
50 | ;
51 |
52 | // Get rid of funny chars
53 | filename = filename.replace(/[\/;]/g, '');
54 | filename = filename.replace(/[^A-Za-z0-9-]/g, '_');
55 |
56 | // Make a Hudson happy package name
57 | pkgname = filename.replace(/\./g, '');
58 | pkgname = pkgname.replace(/_+/g, '.');
59 |
60 | return [ filename, pkgname ];
61 | },
62 |
63 | dumpFile: function(vars, dataKey, filename, component) {
64 | var baseOutputDir = hub.config.outputDir,
65 | path = require('path'),
66 | dir = path.join(baseOutputDir, (common.makeSaneNames(component))[0]);
67 | data = vars[dataKey],
68 | fullFile = path.join(dir, filename),
69 | fs = require('fs')
70 | ;
71 |
72 | hub.emit(hub.LOG, hub.INFO, "Dumping " + fullFile);
73 |
74 | // Any one of these can toss cookies!!!
75 | try {
76 | // This will complain if dir already exists
77 | // And we KNOW we can already make dirs here
78 | fs.mkdirSync(dir, 0777);
79 | } catch(e) {}
80 |
81 | try {
82 | var fd = fs.openSync(fullFile, 'w')
83 | fs.writeSync(fd, data, 0, 'utf8');
84 | fs.closeSync(fd)
85 | return [ fullFile, dir ];
86 | } catch(e) {
87 | hub.emit(hub.LOG, hub.ERROR, "Error dumping file " + fullFile + ": " + e);
88 | }
89 | },
90 | failedTests: function(filename) {
91 | var fs = require('fs'), file;
92 |
93 | try {
94 | file = fs.readFileSync(filename, 'utf8');
95 | return file.match(/failures="[1-9]/);
96 | } catch(e) {
97 | hub.emit(hub.LOG, hub.ERROR, "Error checking for failed unit test: " + e);
98 | return true;
99 | }
100 |
101 | },
102 | takeSeleniumSnapshot: function(test, component) {
103 | var soda = require('soda'), i
104 | , b = soda.createClient({ host: test.sel_host })
105 | , filename = path.join(hub.config.outputDir, (common.makeSaneNames(component))[0], 'snapshot.png')
106 | ;
107 |
108 | if (!test.seleniumID) return;
109 |
110 | b.sid = test.seleniumID;
111 |
112 | b.chain.windowFocus().getEval("window.moveTo(1,0); window.resizeTo(screen.availWidth, screen.availHeight);").end(function(err) {
113 | if (!err) {
114 | b.command('captureScreenshotToString', [], function(err, body, res) {
115 | if (!err) {
116 | var msg;
117 | try {
118 | var bb = new Buffer(body, 'base64'),
119 | msg = "Dumped snapshot for " + test.url + ' to ' + filename + "\n";
120 | fs.writeFileSync(filename, bb, 0, bb.length);
121 | common.addTestOutput(test, msg);
122 | hub.emit(hub.LOG, hub.INFO, msg);
123 | } catch(e) {
124 | msg = "Error dumping snapshot file " + filename + ": " + e + "\n";
125 | common.addTestOutput(test, msg);
126 | hub.emit(hub.LOG, hub.ERROR, msg);
127 | }
128 | }
129 | hub.emit('action:doneDone', err, test);
130 | });
131 | } else {
132 | hub.emit('action:doneDone', err, test);
133 | }
134 | });
135 | },
136 | addTestOutput: function(test, msg) {
137 | var lines = msg.split(/\n/),
138 | now = new Date(),
139 | output = '',
140 | format;
141 |
142 | if (!test) return;
143 |
144 | format = now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate() + ' ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
145 | lines.forEach(function(line) {
146 | output += '[' + format + '] ' + line + "\n";
147 | });
148 | test.output += output;
149 |
150 | if (test.sendOutput && cache.connections[test.browser]) {
151 | // selenium test
152 | cache.connections[test.browser].write(output);
153 | }
154 | if (test.requestKey && cache.connections[test.requestKey]) {
155 | // command line test
156 | cache.connections[test.requestKey].write(output);
157 | }
158 | },
159 | badUnitTest: function(req, test) {
160 | // Dump a FAILED XML file
161 | // Use test file name as the NAME of this test (vs. component name from test itself)
162 | var parts = test.url.split('/');
163 | var name = parts.pop();
164 | name = name.replace(/\..*$/, ''); // get rid of suffix
165 | var names = common.makeSaneNames(common.browserName(req));
166 | var err = 'Test Timed Out: Most likely a Javascript parsing error - try loading URL in your browser',
167 | err = err.replace('BROWSER', names[1]);
168 | err = err.replace('URL', test.url);
169 | var params = { results: err, name: name };
170 | var msg = "Dumped error unit test file " + name + " / " + names[0] + " (from " + test.url + ")";
171 |
172 | hub.emit(hub.LOG, hub.ERROR, msg);
173 | common.addTestOutput(test, msg);
174 |
175 | common.dumpFile(params, 'results', names[0] + '-test.xml', name);
176 | common.dumpFile({ output: test.output }, 'output', names[0] + '.txt', name);
177 | }
178 | };
179 |
180 | return common;
181 | }
182 | };
183 |
184 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/getTest.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | cache = hub.cache
42 | ;
43 |
44 | // Events I care about
45 | hub.addListener('action:get_test', getTest);
46 |
47 | function getTest(req, res) {
48 | var browser = req.session.uuid,
49 | bName = common.browserName(req),
50 | now = new Date().getTime(),
51 | testURL;
52 |
53 | if (!cache.browsers[browser]) {
54 | cache.browsers[browser] = {};
55 | }
56 |
57 | cache.browsers[browser].get_test = now;
58 |
59 | hub.emit(hub.LOG, hub.INFO, 'Getting test for ' + bName);
60 |
61 | for (var i = 0; i < cache.tests_to_run.length; i++) {
62 | var test = cache.tests_to_run[i];
63 | if (test.browser == browser && test.running) {
64 | // um you're already running this test!
65 | // must be something wrong with it - pop it
66 | var error = 'Skipping bad test: ' + test.url + ': we thought it was running!';
67 | hub.emit(hub.LOG, hub.ERROR, error);
68 | common.badUnitTest(req, test);
69 | cache.tests_to_run.splice(i, 1);
70 | i--;
71 | continue;
72 | }
73 |
74 | // This test is not for us
75 | if (test.browser && (test.browser != browser)) continue;
76 |
77 | if (!test.browser) {
78 | // A test pre-loaded w/o any browsers listening
79 | // this browser looks like a winner!
80 | test.browser = browser;
81 | }
82 |
83 | // Otherwise start running this test in capture mode!!
84 | common.addTestOutput(test, "To browser " + bName);
85 | test.running = now;
86 | cache.currentTest[browser] = test;
87 | testURL = test.url;
88 | break;
89 | }
90 |
91 | if (testURL) {
92 | res.writeHead(200, { 'Content-Type': 'application/json' });
93 | res.end(JSON.stringify({ testLocation: testURL }));
94 | hub.emit(hub.LOG, hub.INFO, "Sent test url: " + testURL + ' to ' + bName);
95 | } else {
96 | delete cache.currentTest[browser];
97 | // find all local tests
98 | var glob = require('glob'),
99 | prefix = hub.config.testDir,
100 | local_test_files = hub.config.testRegex,
101 | data = [];
102 | ;
103 |
104 | // No tests for me - end if we're a Selenium browser
105 | if (req.session.selenium) {
106 | // Selenium job all done!!
107 | hub.emit(req.session.uuid + 'finished');
108 | } else {
109 | hub.emit('testsDone');
110 | }
111 |
112 | // ONLY USE HTML FOR NOW UNTIL THE PAGE IS SMARTER...
113 | glob('**/*.html', { cwd: prefix }, function(err, matches_html) {
114 | matches_html.forEach(function(testFile) {
115 | data.push({ test_url: testFile });
116 | });
117 | res.writeHead(200, { 'Content-Type': 'application/json' });
118 | res.end(JSON.stringify({ availableTests: data, config: hub.config }));
119 | });
120 | }
121 | }
122 | }
123 | };
124 |
125 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/heartBeat.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'), cache = hub.cache;
41 |
42 | // Events I care about
43 | hub.addListener('action:heart_beat', heartBeat);
44 |
45 | function heartBeat(req, res) {
46 | var id = req.session.uuid;
47 |
48 | // Update heartbeat time
49 | if (!cache.browsers[id]) {
50 | cache.browsers[id] = {};
51 | }
52 |
53 | cache.browsers[id].heart_beat = new Date().getTime();
54 | cache.browsers[id].name = common.browserName(req);
55 |
56 | hub.on('action:checkedResults', function(results) {
57 | results.current_status = { browsers: cache.browsers, tests_to_run: cache.tests_to_run };
58 | results.config = hub.config;
59 | res.writeHead(200, { 'Content-Type': 'application/json' });
60 | res.end(JSON.stringify(results));
61 | });
62 | hub.emit('action:checkResults', req, res);
63 | }
64 | }
65 | };
66 |
67 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/message.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 | module.exports = {
37 | Create: function(hub, common) {
38 | // A test just dumped to console.error
39 | var path = require('path'),
40 | cache = hub.cache;
41 |
42 | // Events I care about
43 | hub.addListener('action:message', message);
44 |
45 | function message(req, res) {
46 | var obj = req.body,
47 | msg = obj.msg,
48 | why = obj.why,
49 | browser = req.session.uuid, test;
50 |
51 | // Find this test
52 | for (var i = 0; i < cache.tests_to_run.length; i++) {
53 | test = cache.tests_to_run[i];
54 | if (test.browser != browser) continue;
55 | if (test.running) {
56 | common.addTestOutput(test, why + ': ' + msg);
57 | hub.emit(hub.LOG, hub.LOG, 'MESSAGE ' + why + ' from ' + test.url + ': ' + msg);
58 |
59 | break;
60 | }
61 | }
62 |
63 | res.end('OK');
64 | }
65 | }
66 | };
67 |
68 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/pop.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 | module.exports = {
37 | Create: function(hub) {
38 | // Javascript is single threaded! We don't have to worry about concurrency!
39 | var path = require('path');
40 |
41 | // Events I care about
42 | hub.addListener('action:pop', pop);
43 |
44 | // THIS IS DANGEROUS!!!
45 | // Take off top test whatever it is
46 | function pop(req, res) {
47 | hub.cache.tests_to_run.shift();
48 | hub.emit('action:status', req, res);
49 | }
50 | }
51 | };
52 |
53 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/prune.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var TEST_TIME_THRESHOLD = 60000, // 60 seconds to wait before declaring test dead
41 | BROWSER_TIME_THRESHOLD = 20000, // Delete a captured browser after it has been gone for this long - 20 seconds
42 | path = require('path'),
43 | cache = hub.cache
44 | ;
45 |
46 | // Events I care about
47 | hub.addListener('startAction', prune);
48 |
49 | function prune(doing_what, req, res) {
50 | var redirect;
51 |
52 | if (doing_what != 'status') {
53 | prune_browsers(req);
54 | redirect = prune_tests(doing_what, req);
55 | if (redirect) {
56 | // we're done
57 | res.end(JSON.stringify({ redirect_run_tests: '/jute_docs/run_tests.html' }));
58 | } else {
59 | // keep going
60 | hub.emit('action:' + doing_what, req, res);
61 | }
62 | } else {
63 | hub.emit('action:status', req, res);
64 | }
65 | }
66 |
67 | function prune_tests(doing_what, req) {
68 | var now = new Date().getTime(),
69 | browser = req.session.uuid, test,
70 | timeStarted
71 | ;
72 |
73 | // We're already getting a test - let it slide...
74 | if (doing_what == 'get_test') return;
75 |
76 | // Only check my tests
77 | for (var i = 0; i < cache.tests_to_run.length; i++) {
78 | test = cache.tests_to_run[i];
79 | if (test.browser != browser) continue;
80 | timeStarted = test.running;
81 | if (timeStarted) {
82 | if (now - timeStarted > TEST_TIME_THRESHOLD) {
83 | // This test has been running for too long!!
84 | var msg = "Test running for too long - killing it";
85 |
86 | hub.emit(hub.LOG, hub.ERROR, msg);
87 | common.addTestOutput(test, msg);
88 | cache.tests_to_run.splice(i, 1);
89 | common.badUnitTest(req, test);
90 |
91 | // redirect me outta here
92 | return 1;
93 |
94 | }
95 | }
96 | }
97 | if (cache.browsers[browser] && cache.browsers[browser].get_test && (now - cache.browsers[browser].get_test > TEST_TIME_THRESHOLD)) {
98 | // A link test taking too long - these are NOT in cache.tests_to_run
99 | hub.emit(hub.LOG, hub.ERROR, "Test running for too long - killing it");
100 |
101 | // redirect me outta here
102 | return 1;
103 | }
104 | }
105 |
106 | function prune_browsers(req) {
107 | var me = req.session.uuid,
108 | util = require('util');
109 |
110 | // only check other browsers
111 | for (browser in cache.browsers) {
112 | var now = new Date().getTime(),
113 | b_time = cache.browsers[browser].heart_beat;
114 |
115 | if (browser == me) continue;
116 |
117 | if (now - b_time > BROWSER_TIME_THRESHOLD) {
118 | hub.emit(hub.LOG, hub.ERROR, "We lost browser " + cache.browsers[browser].name);
119 | delete cache.browsers[browser];
120 | // take it out of ay tests it's supposed to be running
121 | for (var i = 0; i < cache.tests_to_run.length; i++) {
122 | var test = cache.tests_to_run[i];
123 | if (test.browser == browser) {
124 | // blow this test out!
125 | hub.emit(hub.LOG, hub.ERROR, "Deleting this test that was part of lost browser: " + util.inspect(test));
126 | cache.tests_to_run.splice(i, 1);
127 | i--; // fake a perl 'redo'!! Otherwise we might skip over something!
128 | common.badUnitTest(req, test);
129 | }
130 | }
131 | }
132 | }
133 | }
134 | }
135 | };
136 |
137 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/runTest.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | cache = hub.cache;
42 |
43 | // Events I care about
44 | hub.addListener('action:run_test', runTest);
45 |
46 | function runTest(req, res) {
47 | var uuid = require('node-uuid'),
48 | path = require('path'),
49 | fs = require('fs'),
50 | obj = req.body,
51 | util = require('util'),
52 | tests, multipleFromUI = false,
53 | capture = false,
54 | exec = require('child_process').exec,
55 | errors = []
56 | ;
57 |
58 | hub.emit(hub.LOG, hub.INFO, 'OBJ: ' + util.inspect(obj));
59 | if (obj.test) {
60 | multipleFromUI = true;
61 | // 'run multiple' from UI
62 | if (typeof obj.test == 'object') {
63 | tests = obj.test
64 | } else {
65 | tests = [ obj.test ];
66 | }
67 | } else if (obj.tests) {
68 | // From CLI
69 | tests = obj.tests.split(/\s+/);
70 | }
71 |
72 | if (!tests) {
73 | res.writeHead(302, { Location: "/jute_docs/run_tests.html" });
74 | res.end("/jute_docs/run_tests.html");
75 | return;
76 | }
77 |
78 | // FIRST make sure all these alleged test files exist
79 | for (var i = 0; i < tests.length; i++) {
80 | var realFullFile = path.join(hub.config.testDir, tests[i].replace(/\?.*/, ''));
81 | if (realFullFile.match(/\.html$/)) {
82 | capture = true;
83 | }
84 |
85 | try {
86 | fs.statSync(realFullFile);
87 | } catch (e) {
88 | errors.push(realFullFile);
89 | }
90 | }
91 |
92 | if (errors.length > 0) {
93 | res.writeHead(404);
94 | res.end("Cannot find test files: " + errors.join(', '));
95 | return;
96 | }
97 |
98 | if (!Object.keys(cache.browsers).length && !obj.sel_host && !obj.phantomjs && capture && !obj.load) {
99 | res.writeHead(412);
100 | res.end("There are no currently captured browsers!");
101 | return;
102 | }
103 |
104 | var pushed = false, v8Tests = '',
105 | requestKey = uuid(), seleniumIDs = [];
106 |
107 | // Generate Selenium IDs
108 | if (obj.sel_host || obj.phantomjs) {
109 | var seleniums = parseInt(obj.seleniums, 10) || parseInt(obj.parallel, 10) || 1;
110 | for (var i = 0; i < seleniums; i++) {
111 | seleniumIDs.push(uuid());
112 | }
113 | }
114 |
115 | for (var i = 0; i < tests.length; i++) {
116 | var test = tests[i],
117 | test_obj = {
118 | running: 0,
119 | url: path.join('/', hub.config.testDirWeb, test),
120 | output: '',
121 | requestKey: requestKey,
122 | sendOutput: obj.send_output,
123 | retry: parseInt(obj.retry, 10) || 0
124 | };
125 |
126 | if (test.match(/\.js/)) {
127 | // V8 test!
128 | pushed = true;
129 | exec('JUTE_DEUBG=1 ' + path.join(__dirname, '..', '..', 'jute_v8.js') + ' ' + test + ' 2>&1', function(error, stdout, stderr) {
130 | if (error) {
131 | v8Tests += 'V8 ERROR: ' + error;
132 | } else {
133 | v8Tests += stdout;
134 | }
135 | });
136 | } else if (obj.sel_host) {
137 | // A Selenium Test!
138 |
139 | // keep this around
140 | test_obj.sel_host = obj.sel_host;
141 |
142 | if (obj.send_output) {
143 | test_obj.sendOutput = 1;
144 | }
145 | if (obj.snapshot) {
146 | test_obj.snapshot = 1;
147 | }
148 |
149 | // Only pass these tests out to selenium hosts started by this
150 | // this is how we keep track
151 | // hand this off to next SeleniumID
152 | console.log('choosing selenium id: ' + (i % seleniumIDs.length));
153 | test_obj.browser = seleniumIDs[i % seleniumIDs.length];
154 |
155 | common.addTestOutput(test_obj, 'Selenium test');
156 |
157 | cache.tests_to_run.push(test_obj);
158 | pushed = true;
159 | } else if (obj.phantomjs) {
160 | if (obj.send_output) {
161 | test_obj.sendOutput = 1;
162 | }
163 | if (obj.snapshot) {
164 | test_obj.snapshot = 1;
165 | }
166 |
167 | // Only pass these tests out to phantomjs instances started by this
168 | // this is how we keep track
169 | // hand this off to next SeleniumID
170 | console.log('choosing phantomjs id: ' + (i % seleniumIDs.length));
171 | test_obj.browser = seleniumIDs[i % seleniumIDs.length];
172 |
173 | common.addTestOutput(test_obj, 'PhantomJS test');
174 |
175 | cache.tests_to_run.push(test_obj);
176 | pushed = true;
177 | } else {
178 | if (multipleFromUI) {
179 | // Only run these tests in THIS browser from the UI
180 |
181 | pushed = true;
182 | for (var browser in cache.browsers) {
183 | (function(b) {
184 | hub.emit(hub.LOG, hub.INFO, 'Adding this test to zob: ' + b);
185 | var obj = JSON.parse(JSON.stringify(test_obj));
186 | obj.browser = b;
187 | common.addTestOutput(obj, 'Capture test');
188 | cache.tests_to_run.push(obj);
189 | }(browser));
190 | }
191 | } else {
192 | // Send to each test to each captured browser
193 | if (!obj.load) {
194 | pushed = true;
195 | for (var browser in cache.browsers) {
196 | (function(b) {
197 | hub.emit(hub.LOG, hub.INFO, 'Adding this test to zob: ' + b);
198 | var obj = JSON.parse(JSON.stringify(test_obj));
199 | obj.browser = b;
200 | common.addTestOutput(obj, 'Capture test');
201 | cache.tests_to_run.push(obj);
202 | }(browser));
203 | }
204 | } else {
205 | common.addTestOutput(test_obj, 'Loading this test for any browser');
206 | cache.tests_to_run.push(test_obj);
207 | }
208 | }
209 | }
210 |
211 | common.addTestOutput(test_obj, util.inspect(test_obj));
212 | }
213 |
214 | if (pushed) {
215 | if (obj.sel_host) {
216 | // Start up for a Selenium browser & Listen for results
217 | var totalError = '';
218 | hub.on('action:seleniumDone', function(err, selID) {
219 | seleniumIDs.pop(); // a selenium browser finished - we don't really care which one
220 | // as we're just waiting for all to finish
221 | var done = !seleniumIDs.length;
222 | if (done) hub.removeListener('action:seleniumDone', arguments.callee);
223 |
224 | if (err) {
225 | hub.emit(hub.LOG, hub.ERROR, 'ERROR running Selenium tests (' + selID + '): ' + err);
226 | totalError += err;
227 | if (done) {
228 | res.end(totalError);
229 | }
230 | } else {
231 | if (done) {
232 | hub.once('action:checkedResults', function(results) {
233 | res.end('Final Selenium Results: ' + JSON.stringify(results));
234 | });
235 | hub.emit('action:checkResults');
236 | }
237 | }
238 | });
239 |
240 | seleniumIDs.forEach(function(selID) {
241 | if (obj.sel2) {
242 | hub.emit('action:selenium2Start', selID, req, res);
243 | } else {
244 | hub.emit('action:seleniumStart', selID, req, res);
245 | }
246 | });
247 | } else if (obj.phantomjs) {
248 | // Start up for a Selenium browser & Listen for results
249 | var totalError = '';
250 | hub.on('action:phantomjsDone', function(err, selID) {
251 | seleniumIDs.pop(); // a selenium browser finished - we don't really care which one
252 | // as we're just waiting for all to finish
253 | var done = !seleniumIDs.length;
254 | if (done) hub.removeListener('action:phantomjsDone', arguments.callee);
255 |
256 | if (err) {
257 | hub.emit(hub.LOG, hub.ERROR, 'ERROR running PhantomJS tests (' + selID + '): ' + err);
258 | totalError += err;
259 | if (done) {
260 | res.end(totalError);
261 | }
262 | } else {
263 | if (done) {
264 | hub.once('action:checkedResults', function(results) {
265 | res.end('Final PhantomJS Results: ' + JSON.stringify(results));
266 | });
267 | hub.emit('action:checkResults');
268 | }
269 | }
270 | });
271 |
272 | seleniumIDs.forEach(function(selID) {
273 | hub.emit('action:phantomjsStart', selID, req, res);
274 | });
275 | } else {
276 | // UI wants to run multiple tests - redirect to it!
277 | if (multipleFromUI) {
278 | // Now tell browser to run the tests!
279 | res.writeHead(302, { Location: "/jute_docs/run_tests.html" });
280 | res.end("/jute_docs/run_tests.html");
281 | } else {
282 | // Command line client
283 | if (v8Tests) {
284 | res.write(v8Tests);
285 | }
286 | if (obj.wait) {
287 | cache.connections[requestKey] = res; // our link back to the requesting client for status messages
288 | hub.once('testsDone', function() {
289 | delete cache.connections[requestKey]; // our link back to the requesting client for status messages
290 | res.end('all done!');
291 | });
292 | } else if (capture) {
293 | res.end('Added ' + (obj.test || obj.tests) + ' to capture/load tests');
294 | }
295 | }
296 | }
297 | } else {
298 | if (obj.load) {
299 | res.write('All tests loading and waiting for a browser');
300 | if (obj.wait) {
301 | cache.connections[requestKey] = res; // our link back to the requesting client for status messages
302 | hub.once('testsDone', function() {
303 | delete cache.connections[requestKey]; // our link back to the requesting client for status messages
304 | res.end('all done from load!');
305 | });
306 | } else {
307 | res.end('');
308 | }
309 | } else {
310 | hub.emit(hub.LOG, hub.ERROR, "No browsers listening!");
311 | res.statusCode = 412; // Ye Olde Failed Precondition
312 | res.end('No browsers listening!! Test(s) not added!');
313 | }
314 | }
315 | }
316 | }
317 | };
318 |
319 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/startPhantomjs.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | fs = require('fs'),
42 | child = require('child_process'),
43 | cache = hub.cache
44 | ;
45 |
46 |
47 | // Events I care about
48 | hub.addListener('action:phantomjsStart', startPhantomjs);
49 |
50 | function startPhantomjs(selID, req, res) {
51 | var cb, phantom, body = req.body,
52 | phantomjs = hub.config.phantomjs,
53 | url = 'http://' + (hub.config.host ? hub.config.host + ':' + hub.config.port : req.headers.host) + '/?selenium=' + selID
54 | ;
55 |
56 | try {
57 | hub.emit(hub.LOG, hub.INFO, phantomjs + ' ' + path.join(__dirname, '..', "phantomJUTE.js") + ' ' + url);
58 | phantom = child.spawn(phantomjs, [ path.join(__dirname, '..', "phantomJUTE.js"), url, hub.config.outputDir]);
59 | phantom.stdout.on('data', function(data) {
60 | if (data === 'snapshot') {
61 | hub.emit(hub.LOG, hub.INFO, "SNAPSHOT!");
62 | }
63 | hub.emit(hub.LOG, hub.INFO, "PhantomJS sez: " + data);
64 | common.addTestOutput(cache.currentTest[selID], 'PhantomJS console: ' + data);
65 | });
66 | phantom.stderr.on('data', function(data) {
67 | hub.emit(hub.LOG, hub.ERROR, "PhantomJS stderr: " + data);
68 | common.addTestOutput(cache.currentTest[selID], 'PhantomJS error: ' + data);
69 | });
70 | phantom.on('exit', function() {
71 | if (!phantom.done) {
72 | hub.emit(hub.LOG, hub.ERROR, "PhantomJS exited unexpectedly");
73 | cb('PhantomJS executable exited unexpectedly');
74 | }
75 | });
76 |
77 | } catch(e) {
78 | hub.emit('action:phantomjsDone', 'Cannot start up phantomjs at ' + phantomjs + ': ' + e, selID);
79 | return;
80 | }
81 |
82 | // Give Selenium 1000 minutes to finish - should be good - 16 hours baby!
83 | req.socket.setTimeout(6000000, function() {
84 | hub.emit(hub.LOG, hub.ERROR, 'Phantomjs taking too long - giving up');
85 | cb('took too long!');
86 | });
87 |
88 | cache.connections[selID] = res; // our link back to the requesting client for status messages
89 |
90 | // called when all PhantomJS tests are complete for this instance
91 | // && keep track of requesting client for debug messages back...
92 | // Callback for when the phantomjs process is done
93 | cb = function(err) {
94 | hub.emit(hub.LOG, hub.INFO, 'Phantomjs done!');
95 | phantom.done = true;
96 | phantom.kill();
97 | delete cache.connections[selID]; // done with status updates
98 | hub.emit('action:phantomjsDone', err, selID);
99 | };
100 | hub.once(selID + 'finished', cb);
101 | }
102 | }
103 | };
104 |
105 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/startSelenium.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | fs = require('fs'),
42 | cache = hub.cache
43 | ;
44 |
45 | // Events I care about
46 | hub.addListener('action:seleniumStart', startSelenium);
47 |
48 | function startSelenium(selID, req, res) {
49 | var soda = require('soda'), cb,
50 | body = req.body,
51 | browser
52 | ;
53 |
54 | try {
55 | browser = soda.createClient({
56 | url: 'http://' + (hub.config.host ? hub.config.host + ':' + hub.config.port : req.headers.host),
57 | host: body.sel_host,
58 | browser: body.sel_browser
59 | })
60 | } catch(e) {
61 | hub.emit('action:seleniumDone', 'Cannot connect to Selenium server at ' + body.sel_host + ': ' + e, selID);
62 | return;
63 | }
64 |
65 | // Give Selenium 1000 minutes to finish - should be good - 16 hours baby!
66 | req.socket.setTimeout(60000000, function() {
67 | hub.emit(hub.LOG, hub.ERROR, 'Selenium taking too long - giving up');
68 | cb();
69 | });
70 |
71 | cache.connections[selID] = res; // our link back to the requesting client for status messages
72 |
73 | // called when all Selenium tests are complete for this browser
74 | // && keep track of requesting client for debug messages back...
75 | // Callback for when the Selenium session is done
76 | cb = function(err) {
77 | if (!err) {
78 | browser.chain.testComplete().end(function(err) {
79 | delete cache.connections[selID]; // done with status updates
80 | hub.emit('action:seleniumDone', err, selID);
81 | });
82 | } else {
83 | hub.emit('action:seleniumDone', err, selID);
84 | }
85 | };
86 | cb = hub.once(selID + 'finished', cb);
87 |
88 | browser.
89 | chain.
90 | session().
91 | open('/?selenium=' + selID).
92 | waitForPageToLoad(10000).
93 | end(function(err) {
94 | if (err) {
95 | var msg = 'Error starting/waiting for Selenium page to load: ' + err;
96 | hub.emit('seleniumTestsFinished', err);
97 | } else {
98 | hub.emit(hub.LOG, hub.INFO, "Selenium up and running: " + browser.sid);
99 | // If this is one of the tests that are going to run in the
100 | // Selenium session, tag it with the Selenium token
101 | cache.tests_to_run.forEach(function(test) {
102 | if (test.browser === selID) {
103 | test.seleniumID = browser.sid;
104 | }
105 | });
106 |
107 | }
108 | });
109 | }
110 | }
111 |
112 | };
113 |
114 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/startSelenium2.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | fs = require('fs'),
42 | cache = hub.cache
43 | ;
44 |
45 | // Events I care about
46 | hub.addListener('action:selenium2Start', startSelenium);
47 |
48 | function startSelenium(selID, req, res) {
49 | var webdriverio = require("webdriverio"), cb,
50 | body = req.body, browser
51 | , url = 'http://' + (hub.config.host ? hub.config.host + ':' + hub.config.port : req.headers.host)
52 | ;
53 |
54 | try {
55 | browser = webdriverio.remote({
56 | host: body.sel_host,
57 | port: body.sel_port || 4444,
58 | desiredCapabilities: { browserName: body.sel_browser || 'firefox' }
59 | });
60 |
61 | } catch(e) {
62 | hub.emit('action:seleniumDone', 'Cannot connect to Selenium server at ' + body.sel_host + ': ' + e, selID);
63 | return;
64 | }
65 |
66 | // Give Selenium 1000 minutes to finish - should be good - 16 hours baby!
67 | req.socket.setTimeout(60000000, function() {
68 | hub.emit(hub.LOG, hub.ERROR, 'Selenium taking too long - giving up');
69 | cb();
70 | });
71 |
72 | cache.connections[selID] = res; // our link back to the requesting client for status messages
73 |
74 | // called when all Selenium tests are complete for this browser
75 | // && keep track of requesting client for debug messages back...
76 | // Callback for when the Selenium session is done
77 | cb = function(err) {
78 | hub.removeAllListeners(selID + 'snapshot');
79 | if (!err) {
80 | browser.end(function() {
81 | delete cache.connections[selID]; // done with status updates
82 | hub.emit('action:seleniumDone', err, selID);
83 | });
84 | } else {
85 | hub.emit('action:seleniumDone', err, selID);
86 | }
87 | };
88 | cb = hub.once(selID + 'finished', cb);
89 |
90 | hub.on(selID + 'snapshot', function(test, component) {
91 | browser.screenshot(function(screenshot) {
92 | var path = require('path')
93 | , filename = path.join(hub.config.outputDir, (common.makeSaneNames(component))[0], 'snapshot.png');
94 |
95 | try {
96 | var bb = new Buffer(screenshot.value, 'base64'),
97 | msg = "Dumped snapshot for " + test.url + ' to ' + filename + "\n";
98 | fs.writeFileSync(filename, bb, 0, bb.length);
99 | common.addTestOutput(test, msg);
100 | hub.emit(hub.LOG, hub.INFO, msg);
101 | } catch(e) {
102 | msg = "Error dumping snapshot file " + filename + ": " + e + "\n";
103 | common.addTestOutput(test, msg);
104 | hub.emit(hub.LOG, hub.ERROR, msg);
105 | }
106 |
107 | hub.emit('action:doneDone', null, test);
108 | });
109 | });
110 |
111 | browser
112 | .init(function() {
113 | // If this is one of the tests that are going to run in the
114 | // Selenium session, tag it with the Selenium token
115 | cache.tests_to_run.forEach(function(test) {
116 | if (test.browser === selID) {
117 | test.seleniumID = browser.sessionId;
118 | test.sel2 = true;
119 | }
120 | });
121 | })
122 | .url(url + '/?selenium=' + selID);
123 | }
124 | }
125 |
126 | };
127 |
128 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/status.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | cache = hub.cache;
42 |
43 | // Events I care about
44 | hub.addListener('action:checkResults', checkResults);
45 |
46 | hub.addListener('action:status', function(req, res) {
47 | hub.once('action:checkedResults', function(results) {
48 | results.current_status = { browsers: cache.browsers, tests_to_run: cache.tests_to_run };
49 | results.config = hub.config;
50 | res.end(JSON.stringify(results));
51 | });
52 | hub.emit('action:checkResults');
53 | });
54 |
55 | function checkResults() {
56 | var baseDir = hub.config.outputDir,
57 | fs = require('fs'),
58 | path = require('path'),
59 | ret = { current_results: {} };
60 |
61 | try {
62 | // Find & parse all results
63 | var components = fs.readdirSync(baseDir);
64 |
65 | if (components.length) {
66 | components.forEach(function(component) {
67 | doComp(ret, component, function() {
68 | if (Object.keys(ret.current_results).length == components.length) {
69 | hub.emit('action:checkedResults', ret);
70 | }
71 | });
72 | });
73 | } else {
74 | hub.emit('action:checkedResults', ret);
75 | }
76 | } catch(e) {
77 | hub.emit(hub.LOG, hub.ERROR, 'Error getting current results from ' + baseDir + ': ' + e);
78 | hub.emit('action:checkedResults', ret);
79 | }
80 | }
81 |
82 | function doComp(ret, component, cb) {
83 | var testFiles, testResults = [], compDir,
84 | glob = require('glob'),
85 | fs = require('fs'),
86 | baseDir = hub.config.outputDir;
87 |
88 | component = path.basename(component);
89 | compDir = path.join(baseDir, component);
90 |
91 | // Find all the various output files
92 | glob('**/*.txt', { cwd: compDir }, function(err, debugFiles) {
93 | glob('**/*.png', { cwd: compDir }, function(err, snapshotFiles) {
94 | glob('**/*.xml', { cwd: compDir }, function(err, testFiles) {
95 | // Determined if failed or not
96 | if (!err) {
97 | if (testFiles && testFiles.length) {
98 | testFiles.forEach(function(testFile) {
99 | if (common.failedTests(path.join(compDir, testFile))) {
100 | testResults.push({ name: testFile, failed: 1 });
101 | } else {
102 | testResults.push({ name: testFile, failed: 0 });
103 | }
104 | });
105 | }
106 |
107 | try {
108 | var coverage = fs.existsSync(path.join(baseDir, component, 'lcov-report'));
109 | ret.current_results[component] = {};
110 | ret.current_results[component].test_results = testResults;
111 | ret.current_results[component].coverage = coverage;
112 | ret.current_results[component].debugFiles = debugFiles.map(function(f) { return f; });
113 | ret.current_results[component].snapshotFiles = snapshotFiles.map(function(f) { return f; });
114 | } catch(e) {
115 | hub.emit(hub.LOG, hub.ERROR, 'Error checking for coverage path: ' + e);
116 | }
117 | } else {
118 | hub.emit(hub.LOG, hub.ERROR, 'Error getting current output files: ' + err);
119 | }
120 | cb();
121 | });
122 | });
123 | });
124 | }
125 | }
126 | };
127 |
128 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/testReport.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub, common) {
39 | // Javascript is single threaded! We don't have to worry about concurrency!
40 | var path = require('path'),
41 | cache = hub.cache;
42 |
43 | // Events I care about
44 | hub.addListener('action:test_report', testReport);
45 | hub.addListener('testOutputDone', testOutputDone);
46 |
47 | function testReport(req, res) {
48 | var obj = req.body,
49 | succeeded = true,
50 | names = common.makeSaneNames(common.browserName(req)),
51 | filename = names[0],
52 | pkgname = names[1],
53 | output = '',
54 | exec = require('child_process').exec
55 | ;
56 |
57 | // obj = { results: , name: , coverage: }
58 | obj.results = obj.results.replace(/testsuite name="/g, 'testsuite name="' + pkgname + '.');
59 |
60 | if (obj.name) {
61 | names = common.dumpFile(obj, 'results', filename + '-test.xml', obj.name);
62 | if (common.failedTests(names[0])) {
63 | succeeded = false;
64 | }
65 | hub.emit(hub.LOG, hub.INFO, "Test Report for " + obj.name);
66 | output += "Test Report for " + obj.name + "\n";
67 | output += 'It: ' + (succeeded ? 'succeeded' : 'failed') + "\n";
68 |
69 | }
70 |
71 | if (obj.log) {
72 | var log = JSON.parse(obj.log);
73 | output += "------------ START CONSOLE OUTPUT ------------\n";
74 | log.forEach(function(msg) {
75 | output += msg.msg + "\n";
76 | });
77 | output += "------------ END CONSOLE OUTPUT ------------\n";
78 | }
79 |
80 | if (obj.coverage && obj.coverage !== 'null') {
81 | try {
82 | var cover_obj = JSON.parse(obj.coverage);
83 | for (file in cover_obj) {
84 | var new_file = path.join(hub.config.outputDir, obj.name, 'lcov-report', file);
85 | cover_obj[new_file] = cover_obj[file];
86 | delete cover_obj[file];
87 | }
88 | obj.coverage = JSON.stringify(cover_obj);
89 | var namez = common.dumpFile(obj, 'coverage', 'cover.json', obj.name);
90 | exec(hub.config.java + ' -jar ' + path.join(__dirname, "yuitest-coverage-report.jar") + " -o " + namez[1] + " --format lcov " + namez[0],
91 | function(error, stdout, stderr) {
92 | var msg;
93 | if (error) {
94 | msg = "Error generating cooverage Report for " + obj.name + ': ' + error + "\n";
95 | output += msg;
96 | hub.emit(hub.LOG, hub.ERROR, msg);
97 | } else {
98 | msg = "Generated cooverage Report for " + obj.name + "\n";
99 | hub.emit(hub.LOG, hub.INFO, msg);
100 | output += msg;
101 |
102 | /// deteremine coverage
103 | for (file in cover_obj) {
104 | cover = cover_obj[file];
105 | total_lines = cover.coveredLines;
106 | total_functions = cover.coveredFunctions;
107 |
108 | if (total_lines) {
109 | line_coverage = Math.round((cover.calledLines / total_lines) * 100);
110 | output += 'Line coverage for ' + path.basename(file) + ': ' + line_coverage + '%\n';
111 | }
112 |
113 | if (total_functions) {
114 | func_coverage = Math.round((cover.calledFunctions / total_functions) * 100);
115 | output += 'Function coverage for ' + path.basename(file) + ': ' + func_coverage + '%\n';
116 | }
117 | }
118 | ///// determine coverage
119 | }
120 |
121 | hub.emit('testOutputDone', req, res, succeeded, output);
122 | }
123 | );
124 |
125 | } catch(e) {
126 | hub.emit(hub.LOG, hub.ERROR, "Error generating coverage report: " + e);
127 | output += "Error generating coverage report: " + e;
128 | hub.emit('testOutputDone', req, res, succeeded, output);
129 | }
130 | } else {
131 | hub.emit('testOutputDone', req, res, succeeded, output);
132 | }
133 | }
134 |
135 | function testOutputDone(req, res, succeeded, output) {
136 | // Take this test out of circulation
137 | var totalTests = cache.tests_to_run.length,
138 | names = common.makeSaneNames(common.browserName(req)),
139 | now = new Date().getTime(),
140 | obj = req.body;
141 |
142 | for (var i = 0; i < totalTests; i++) {
143 | var test = cache.tests_to_run[i];
144 |
145 | if (test.browser == req.session.uuid) {
146 | // This is the test that just finished
147 | hub.once('action:doneDone', function(err, test) {
148 | if (err) {
149 | hub.emit(hub.LOG, hub.ERROR, err);
150 | } else {
151 | hub.emit(hub.LOG, hub.INFO, 'Test finished: ' + test.url);
152 | }
153 | common.dumpFile({ output: test.output }, 'output', path.basename(names[0], 'xml') + '.txt', obj.name);
154 | res.writeHead(200, { 'Content-Type': 'text/plain' });
155 | res.end('OK');
156 | });
157 |
158 | // Clear this test out
159 | common.addTestOutput(test, output);
160 | common.addTestOutput(test, obj.name + " finished - it " +
161 | (succeeded ? 'SUCCEEDED' : 'FAILED') + ' - it took ' +
162 | (now - test.running) + "ms\n");
163 |
164 | if (test.retry && !succeeded) {
165 | common.addTestOutput(test, 'Test failed - trying it ' + test.retry + ' more times');
166 | common.addTestOutput(test, '--------------------------------------------------------------------------------------');
167 | test.retry--;
168 | test.running = 0;
169 | } else {
170 | cache.tests_to_run.splice(i, 1);
171 | }
172 |
173 | // Take a snapshot & wait or we're done - always if 'snapshot' is set otherwise
174 | // only if a test fails
175 | if ((!succeeded || test.snapshot) && req.session.selenium) {
176 | hub.emit(hub.LOG, hub.INFO, 'Taking a Selenium snapshot of: ' + test.url);
177 | if (test.sel2) {
178 | hub.emit(test.browser + 'snapshot', test, obj.name);
179 | } else {
180 | common.takeSeleniumSnapshot(test, obj.name);
181 | }
182 | } else {
183 | hub.emit('action:doneDone', null, test);
184 | }
185 | break;
186 | }
187 | }
188 |
189 | if (!totalTests) {
190 | // A single browser test
191 | output += obj.name + " finished - it " + (succeeded ? 'SUCCEEDED' : 'FAILED') + "\n";
192 | common.dumpFile({ output: output }, 'output', path.basename(names[0], 'xml') + '.txt', obj.name);
193 | res.end('OK');
194 | }
195 |
196 | }
197 | }
198 | };
199 |
200 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/actions/yuitest-coverage-report.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzo/JUTE/77527d0a377077038b2b81aabe8f6b8d2a37f90a/backend/nodejute/jute/actions/yuitest-coverage-report.jar
--------------------------------------------------------------------------------
/backend/nodejute/jute/configure.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 |
37 | module.exports = {
38 | Create: function(hub) {
39 | path = require('path');
40 |
41 | // Events I care about
42 | hub.addListener('configure', configure);
43 |
44 | function configure() {
45 |
46 | var config = {
47 | port: 5883,
48 | docRoot: '/var/www',
49 | testDir: 'test/',
50 | outputDir: 'output/',
51 | java: '',
52 | logFormat: '',
53 | logFile: '/tmp/jute.log',
54 | testRegex: '.html$',
55 | inject: 1,
56 | phantomjs: '/usr/local/bin/phantomjs',
57 | host: ''
58 | },
59 | exec = require('child_process').exec,
60 | fs = require('fs');
61 |
62 | hub.config = config;
63 |
64 | // Suck in NPM config variables
65 | for (var key in config) {
66 | var val = process.env['npm_package_config_' + key];
67 | if (val) {
68 | config[key] = val;
69 | }
70 | }
71 |
72 | try {
73 | config.logFD = fs.openSync(config.logFile, "w");
74 | } catch(e) {
75 | console.error('Cannot open logilfe: ' + e);
76 | hub.emit('configureError', { name: 'logFile', value: config.logFile, error: e } );
77 | return;
78 | }
79 |
80 | try {
81 | var stat = fs.statSync(config.docRoot);
82 | if (!stat.isDirectory()) {
83 | throw 'foobie';
84 | }
85 | } catch(e) {
86 | hub.emit(hub.LOG, hub.ERROR, "** " + config.docRoot + " does not exist or is not a directory!! **");
87 | hub.emit(hub.LOG, hub.ERROR, "Set it properly: npm config set jute:docRoot ");
88 | hub.emit('configureError', { name: 'docRoot', value: config.docRoot, error: e } );
89 | return;
90 | }
91 |
92 | // Web paths and full paths...
93 | config.outputDirWeb = config.outputDir;
94 | config.outputDir = path.join(config.docRoot, config.outputDir);
95 | try {
96 | fs.statSync(config.outputDir);
97 | } catch(e) {
98 | try {
99 | fs.mkdirSync(config.outputDir, 0777)
100 | } catch(e2) {
101 | hub.emit(hub.LOG, hub.ERROR, "Cannot make output dir: " + e2);
102 | hub.emit('configureError', { name: 'outputDir', value: config.outputDir, error: e2 } );
103 | return;
104 | }
105 | }
106 |
107 | config.testDirWeb = config.testDir;
108 | if (!config.testDirWeb.match(/\/$/)) {
109 | config.testDirWeb += '/';
110 | }
111 |
112 | config.testDir = path.join(config.docRoot, config.testDir);
113 |
114 | try {
115 | fs.statSync(config.testDir);
116 | } catch(e) {
117 | try {
118 | fs.mkdirSync(config.testDir, 0777)
119 | } catch(e2) {
120 | hub.emit(hub.LOG, hub.ERROR, "Cannot make test dir: " + e2);
121 | hub.emit('configureError', { name: 'testDir', value: config.testDir, error: e2 } );
122 | return;
123 | }
124 | }
125 |
126 | // Find Java executable
127 | if (!config.java) {
128 | exec('which java', function (error, stdout, stderr) {
129 | if (!error) {
130 | config.java = stdout.trim();
131 | }
132 | try {
133 | var stat = fs.statSync(config.java);
134 | if (!stat.isFile()) {
135 | throw 'foobie';
136 | }
137 | } catch(e) {
138 | hub.emit(hub.LOG, hub.ERROR, '** Cannot find "java" executable in PATH **');
139 | hub.emit(hub.LOG, hub.ERROR, 'Set the "java" configuration variable (% npm config set jute:java )');
140 | hub.emit(hub.LOG, hub.ERROR, 'Or add the "java" executable to your PATH');
141 | hub.emit('configureError', { name: 'java', value: config.java, error: e } );
142 | return;
143 | }
144 | });
145 | } else {
146 | try {
147 | var stat = fs.statSync(config.java);
148 | if (!stat.isFile()) {
149 | throw 'foobie';
150 | }
151 | } catch(e) {
152 | hub.emit(hub.LOG, hub.ERROR, '** Cannot find "java" executable **');
153 | hub.emit(hub.LOG, hub.ERROR, 'NPM java config variable improperly set: ' + config.java);
154 | hub.emit('configureError', { name: 'java', value: config.java, error: e } );
155 | return;
156 | }
157 | }
158 |
159 | // Make sure output directory is writable for grins...
160 | var testDir = path.join(config.outputDir, 'foo');
161 | try {
162 | fs.mkdirSync(testDir, 0777);
163 | } catch(e) {
164 | hub.emit(hub.LOG, hub.ERROR, "** Output directory '" + config.outputDir + "' not writable or does not exist!! **");
165 | hub.emit(hub.LOG, hub.ERROR, "Note outputDir is RELATIVE to docRoot!!");
166 | hub.emit(hub.LOG, hub.ERROR, "Change output dir using: % npm conifg set jute:outputDir ");
167 | hub.emit(hub.LOG, hub.ERROR, "Or make " + config.outputDir + ' writable by user/group running jute');
168 | hub.emit('configureError', { name: 'outputDir', value: config.outputDir, error: e } );
169 | return;
170 | }
171 |
172 | try {
173 | fs.rmdirSync(testDir);
174 | } catch(e) {}
175 |
176 | // All is cool - stash config & move on
177 | hub.config = config;
178 | hub.emit('configureDone', config);
179 | }
180 | }
181 | };
182 |
183 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/daemon.js:
--------------------------------------------------------------------------------
1 | #!env node
2 |
3 | var opt = require( "optimist"),
4 | fs = require('fs'),
5 | args = opt
6 | .usage('Usage: $0 [ --start ] [ --stop ] [ --restart ] [ --kill ]')
7 | .alias('s', 'start')
8 | .alias('p', 'stop')
9 | .alias('r', 'restart')
10 | .alias('k', 'kill')
11 | .describe('start', 'Start JUTE')
12 | .describe('stop', 'Stop JUTE')
13 | .argv,
14 | pidfile = process.env['npm_package_config_pidfile'] || '/tmp/jute.pid'
15 | user = process.env['npm_package_config_asuser'] || ''
16 | ;
17 |
18 | var daemon = require("daemonize2").setup({
19 | main: "../jute_backend.js"
20 | , name: "jute"
21 | , pidfile: pidfile
22 | , user: user
23 | });
24 |
25 | if (args.start) {
26 | daemon.start().once("started", function() {
27 | process.exit();
28 | });
29 | } else if (args.stop) {
30 | daemon.stop();
31 | } else if (args.restart) {
32 | if (daemon.status()) {
33 | daemon.stop().once("stopped", function() {
34 | daemon.start().once("started", function() {
35 | process.exit();
36 | });
37 | });
38 | } else {
39 | daemon.start().once("started", function() {
40 | process.exit();
41 | });
42 | }
43 | } else if (args.kill) {
44 | daemon.kill();
45 | } else {
46 | console.error("You must specify 'start' or 'stop'!");
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/jute_docs/capture.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | JUTE - Javascript Unit Test Environment
8 |
103 |
104 |
105 |
106 |
107 |
108 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/backend/nodejute/jute/jute_docs/jute.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011, Yahoo! Inc.
3 | All rights reserved.
4 |
5 | Redistribution and use of this software in source and binary forms,
6 | with or without modification, are permitted provided that the following
7 | conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Yahoo! Inc. nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Yahoo! Inc.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 | */
35 |
36 | YUI().add('jute', function(Y) {
37 | var UT = Y.namespace('UnitTest'), button, load_button, kick_button, clear_button, clear_results;
38 |
39 | UT.heartBeat = function() {
40 | var cfg = {
41 | method: 'GET',
42 | on: {
43 | success: function (transactionid, response) {
44 | var obj, current_status, current_results, status_output, result_output, i,
45 | test, color, errorCount = 0;
46 | try {
47 | obj = Y.JSON.parse(response.responseText);
48 | if (typeof(obj.redirect_run_tests) === 'string') {
49 | // kick the run_tests iframe
50 | Y.one('#run_tests').setAttribute('src', obj.redirect_run_tests);
51 | } else {
52 | current_status = obj.current_status;
53 | current_results = obj.current_results;
54 |
55 | // Make test/browser output pretty
56 | status_output = '