lab_bench 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -2
- data/Gemfile.lock +25 -0
- data/README.rdoc +20 -0
- data/VERSION +1 -1
- data/assets/css/app.css +28 -2
- data/assets/images/connect.png +0 -0
- data/assets/images/disconnect.png +0 -0
- data/assets/js/app.js +54 -48
- data/assets/js/underscore-min.js +25 -0
- data/assets/views/index.haml +16 -0
- data/bin/lab_bench_server +26 -4
- data/lab_bench.gemspec +114 -0
- metadata +136 -22
- data/assets/index.html +0 -18
data/Gemfile
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
+
|
2
3
|
# Add dependencies required to use your gem here.
|
3
|
-
|
4
|
-
|
4
|
+
gem 'haml', '~> 2.2.0'
|
5
|
+
gem 'sinatra', '~> 1.1.0'
|
6
|
+
gem 'eventmachine', '~> 0.12.10'
|
7
|
+
gem 'em-websocket', '~> 0.2.0'
|
8
|
+
gem 'thin', '~> 1.2.0'
|
9
|
+
gem 'yajl-ruby', '~> 0.7.8'
|
5
10
|
|
6
11
|
# Add dependencies to develop your gem here.
|
7
12
|
# Include everything needed to run rake, tests, features, etc.
|
@@ -10,4 +15,5 @@ group :development do
|
|
10
15
|
gem "bundler", "~> 1.0.0"
|
11
16
|
gem "jeweler", "~> 1.5.1"
|
12
17
|
gem "rcov", ">= 0"
|
18
|
+
gem 'hpricot'
|
13
19
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,45 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
addressable (2.2.2)
|
5
|
+
daemons (1.1.0)
|
6
|
+
em-websocket (0.2.0)
|
7
|
+
addressable (>= 2.1.1)
|
8
|
+
eventmachine (>= 0.12.9)
|
9
|
+
eventmachine (0.12.10)
|
4
10
|
git (1.2.5)
|
11
|
+
haml (2.2.24)
|
12
|
+
hpricot (0.8.3)
|
5
13
|
jeweler (1.5.1)
|
6
14
|
bundler (~> 1.0.0)
|
7
15
|
git (>= 1.2.5)
|
8
16
|
rake
|
17
|
+
rack (1.2.1)
|
9
18
|
rake (0.8.7)
|
10
19
|
rcov (0.9.9)
|
11
20
|
shoulda (2.11.3)
|
21
|
+
sinatra (1.1.0)
|
22
|
+
rack (~> 1.1)
|
23
|
+
tilt (~> 1.1)
|
24
|
+
thin (1.2.7)
|
25
|
+
daemons (>= 1.0.9)
|
26
|
+
eventmachine (>= 0.12.6)
|
27
|
+
rack (>= 1.0.0)
|
28
|
+
tilt (1.1)
|
29
|
+
yajl-ruby (0.7.8)
|
12
30
|
|
13
31
|
PLATFORMS
|
14
32
|
ruby
|
15
33
|
|
16
34
|
DEPENDENCIES
|
17
35
|
bundler (~> 1.0.0)
|
36
|
+
em-websocket (~> 0.2.0)
|
37
|
+
eventmachine (~> 0.12.10)
|
38
|
+
haml (~> 2.2.0)
|
39
|
+
hpricot
|
18
40
|
jeweler (~> 1.5.1)
|
19
41
|
rcov
|
20
42
|
shoulda
|
43
|
+
sinatra (~> 1.1.0)
|
44
|
+
thin (~> 1.2.0)
|
45
|
+
yajl-ruby (~> 0.7.8)
|
data/README.rdoc
CHANGED
@@ -2,8 +2,28 @@
|
|
2
2
|
|
3
3
|
A browser-based runner for ruby Test::Unit tests.
|
4
4
|
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Install the gem:
|
8
|
+
|
9
|
+
<tt>gem install lab_bench</tt>
|
10
|
+
|
11
|
+
If you're using Rails 2.x, add this to config/environment.rb:
|
12
|
+
|
13
|
+
<tt>config.gem 'lab_bench'</tt>
|
14
|
+
|
15
|
+
Start the server in a new console / screen:
|
16
|
+
|
17
|
+
<tt>lab_bench_server</tt>
|
18
|
+
|
19
|
+
Send your browser to http://localhost:9020/ then run your tests like this:
|
20
|
+
|
21
|
+
<tt>rake test TESTOPTS="--runner=lab_bench"</tt>
|
22
|
+
|
5
23
|
== TODO
|
6
24
|
|
25
|
+
* Buffer test events in server and replay to new browser clients so they can start "hot"
|
26
|
+
* Browser should show whether it is connected to the server and reconnect if it dies
|
7
27
|
* Show me test failures as they happen
|
8
28
|
* Give me more context on the test suite (names of files being run, command line, project directory, etc)
|
9
29
|
* Allow me to rerun a suite
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/assets/css/app.css
CHANGED
@@ -1,9 +1,35 @@
|
|
1
|
+
appstatus {
|
2
|
+
display: block;
|
3
|
+
height: 5%;
|
4
|
+
position: fixed;
|
5
|
+
top: 0;
|
6
|
+
left: 0;
|
7
|
+
right: 0;
|
8
|
+
padding: 2px;
|
9
|
+
padding-left: 30px;
|
10
|
+
background-image: url(/images/disconnect.png);
|
11
|
+
background-repeat: no-repeat;
|
12
|
+
background-position: 6px 13px;
|
13
|
+
background-color: #222;
|
14
|
+
color: white;
|
15
|
+
font-size: 1.6em;
|
16
|
+
line-height: 1.6em;
|
17
|
+
}
|
18
|
+
|
19
|
+
appstatus.backfilling {
|
20
|
+
background-image: url(/images/spinner.gif);
|
21
|
+
}
|
22
|
+
|
23
|
+
appstatus.realtime {
|
24
|
+
background-image: url(/images/connect.png);
|
25
|
+
}
|
26
|
+
|
1
27
|
testruns {
|
2
28
|
display: block;
|
3
29
|
overflow-y: scroll;
|
4
|
-
height:
|
30
|
+
height: 60%;
|
5
31
|
position: fixed;
|
6
|
-
top:
|
32
|
+
top: 6%;
|
7
33
|
left: 0;
|
8
34
|
right: 0;
|
9
35
|
}
|
Binary file
|
Binary file
|
data/assets/js/app.js
CHANGED
@@ -31,58 +31,64 @@ head.ready(function(){
|
|
31
31
|
socket.onmessage = function(jsonMessage) {
|
32
32
|
if (jsonMessage && jsonMessage.data) {
|
33
33
|
var message = $.parseJSON(jsonMessage.data);
|
34
|
+
|
35
|
+
if (_.isEqual(message, ['backfilling'])) {
|
36
|
+
$('appstatus').attr('class', 'backfilling');
|
37
|
+
} else if (_.isEqual(message,['realtime'])) {
|
38
|
+
$('appstatus').attr('class', 'realtime');
|
39
|
+
} else {
|
40
|
+
// append message to event log
|
41
|
+
message.timestamp = new Date(message.milliseconds).toLocaleTimeString();
|
42
|
+
var template = templates[message.event];
|
43
|
+
$('eventlog')
|
44
|
+
.append(Mustache.to_html(template, message))
|
45
|
+
.scrollTop($('eventlog').attr('scrollHeight') - $('eventlog').height());
|
34
46
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
.scrollTop($('eventlog').attr('scrollHeight') - $('eventlog').height());
|
41
|
-
|
42
|
-
// find or create the corresponding suite
|
43
|
-
var guid = message.guid;
|
44
|
-
if ($('#' + guid).length == 0) {
|
45
|
-
$('testruns').prepend('<testrun id=' + guid + '>');
|
46
|
-
}
|
47
|
+
// find or create the corresponding suite
|
48
|
+
var guid = message.guid;
|
49
|
+
if ($('#' + guid).length == 0) {
|
50
|
+
$('testruns').prepend('<testrun id=' + guid + '>');
|
51
|
+
}
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
53
|
+
// update its data based on the event
|
54
|
+
var testrun = $('#' + guid);
|
55
|
+
var testrunData = testrun.data();
|
56
|
+
if (message.event === "Test::Unit::UI::TestRunnerMediator::STARTED") {
|
57
|
+
testrunData.guid = guid;
|
58
|
+
testrunData.timestamp = new Date(message.milliseconds).toLocaleTimeString();
|
59
|
+
testrunData.status = 'Initializing';
|
60
|
+
testrunData.testCount = 0;
|
61
|
+
testrunData.failedCount = 0;
|
62
|
+
} else if (message.event === "Test::Unit::TestCase::STARTED") {
|
63
|
+
testrunData.status = 'Running';
|
64
|
+
testrunData.currentTest = message.args;
|
65
|
+
testrunData.running = true;
|
66
|
+
} else if (message.event === "FAULT") {
|
67
|
+
testrunData.failedCount += 1;
|
68
|
+
} else if (message.event === "Test::Unit::TestCase::FINISHED") {
|
69
|
+
testrunData.running = false;
|
70
|
+
testrunData.testCount += 1;
|
71
|
+
} else if (message.event === "Test::Unit::UI::TestRunnerMediator::FINISHED") {
|
72
|
+
if (testrunData.failedCount == 0) {
|
73
|
+
testrunData.status = 'Success';
|
74
|
+
} else {
|
75
|
+
testrunData.status = 'Failed';
|
76
|
+
}
|
71
77
|
}
|
72
|
-
}
|
73
78
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
// rerender the suite based on the updated data
|
80
|
+
testrun.html(Mustache.to_html("\
|
81
|
+
<testrunsummary class='{{status}}'> \
|
82
|
+
<started>Test Run Started {{timestamp}} - {{status}}</started> \
|
83
|
+
{{#running}} \
|
84
|
+
<currenttest>Current Test: {{currentTest}}</currenttest> \
|
85
|
+
{{/running}} \
|
86
|
+
<statistics> \
|
87
|
+
<testcount>{{testCount}} total test(s)</testcount> \
|
88
|
+
<failedcount>{{failedCount}} failure(s)</failedcount> \
|
89
|
+
</statistics> \
|
90
|
+
</testrunsummary>", testrunData));
|
91
|
+
}
|
86
92
|
}
|
87
93
|
};
|
88
94
|
});
|
@@ -0,0 +1,25 @@
|
|
1
|
+
// Underscore.js 1.1.3
|
2
|
+
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
|
3
|
+
// Underscore is freely distributable under the MIT license.
|
4
|
+
// Portions of Underscore are inspired or borrowed from Prototype,
|
5
|
+
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
6
|
+
// For all details and documentation:
|
7
|
+
// http://documentcloud.github.com/underscore
|
8
|
+
(function(){var p=this,C=p._,m={},j=Array.prototype,n=Object.prototype,i=j.slice,D=j.unshift,E=n.toString,q=n.hasOwnProperty,s=j.forEach,t=j.map,u=j.reduce,v=j.reduceRight,w=j.filter,x=j.every,y=j.some,o=j.indexOf,z=j.lastIndexOf;n=Array.isArray;var F=Object.keys,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else p._=c;c.VERSION="1.1.3";var k=c.each=c.forEach=function(a,b,d){if(s&&a.forEach===s)a.forEach(b,d);else if(c.isNumber(a.length))for(var e=
|
9
|
+
0,f=a.length;e<f;e++){if(b.call(d,a[e],e,a)===m)break}else for(e in a)if(q.call(a,e))if(b.call(d,a[e],e,a)===m)break};c.map=function(a,b,d){if(t&&a.map===t)return a.map(b,d);var e=[];k(a,function(f,g,h){e[e.length]=b.call(d,f,g,h)});return e};c.reduce=c.foldl=c.inject=function(a,b,d,e){var f=d!==void 0;if(u&&a.reduce===u){if(e)b=c.bind(b,e);return f?a.reduce(b,d):a.reduce(b)}k(a,function(g,h,G){d=!f&&h===0?g:b.call(e,d,g,h,G)});return d};c.reduceRight=c.foldr=function(a,b,d,e){if(v&&a.reduceRight===
|
10
|
+
v){if(e)b=c.bind(b,e);return d!==void 0?a.reduceRight(b,d):a.reduceRight(b)}a=(c.isArray(a)?a.slice():c.toArray(a)).reverse();return c.reduce(a,b,d,e)};c.find=c.detect=function(a,b,d){var e;A(a,function(f,g,h){if(b.call(d,f,g,h)){e=f;return true}});return e};c.filter=c.select=function(a,b,d){if(w&&a.filter===w)return a.filter(b,d);var e=[];k(a,function(f,g,h){if(b.call(d,f,g,h))e[e.length]=f});return e};c.reject=function(a,b,d){var e=[];k(a,function(f,g,h){b.call(d,f,g,h)||(e[e.length]=f)});return e};
|
11
|
+
c.every=c.all=function(a,b,d){b=b||c.identity;if(x&&a.every===x)return a.every(b,d);var e=true;k(a,function(f,g,h){if(!(e=e&&b.call(d,f,g,h)))return m});return e};var A=c.some=c.any=function(a,b,d){b=b||c.identity;if(y&&a.some===y)return a.some(b,d);var e=false;k(a,function(f,g,h){if(e=b.call(d,f,g,h))return m});return e};c.include=c.contains=function(a,b){if(o&&a.indexOf===o)return a.indexOf(b)!=-1;var d=false;A(a,function(e){if(d=e===b)return true});return d};c.invoke=function(a,b){var d=i.call(arguments,
|
12
|
+
2);return c.map(a,function(e){return(b?e[b]:e).apply(e,d)})};c.pluck=function(a,b){return c.map(a,function(d){return d[b]})};c.max=function(a,b,d){if(!b&&c.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};k(a,function(f,g,h){g=b?b.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});
|
13
|
+
return e.value};c.sortBy=function(a,b,d){return c.pluck(c.map(a,function(e,f,g){return{value:e,criteria:b.call(d,e,f,g)}}).sort(function(e,f){var g=e.criteria,h=f.criteria;return g<h?-1:g>h?1:0}),"value")};c.sortedIndex=function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(b)?e=g+1:f=g}return e};c.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(c.isArray(a))return a;if(c.isArguments(a))return i.call(a);return c.values(a)};c.size=function(a){return c.toArray(a).length};
|
14
|
+
c.first=c.head=function(a,b,d){return b&&!d?i.call(a,0,b):a[0]};c.rest=c.tail=function(a,b,d){return i.call(a,c.isUndefined(b)||d?1:b)};c.last=function(a){return a[a.length-1]};c.compact=function(a){return c.filter(a,function(b){return!!b})};c.flatten=function(a){return c.reduce(a,function(b,d){if(c.isArray(d))return b.concat(c.flatten(d));b[b.length]=d;return b},[])};c.without=function(a){var b=i.call(arguments,1);return c.filter(a,function(d){return!c.include(b,d)})};c.uniq=c.unique=function(a,
|
15
|
+
b){return c.reduce(a,function(d,e,f){if(0==f||(b===true?c.last(d)!=e:!c.include(d,e)))d[d.length]=e;return d},[])};c.intersect=function(a){var b=i.call(arguments,1);return c.filter(c.uniq(a),function(d){return c.every(b,function(e){return c.indexOf(e,d)>=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e<b;e++)d[e]=c.pluck(a,""+e);return d};c.indexOf=function(a,b){if(o&&a.indexOf===o)return a.indexOf(b);for(var d=0,e=a.length;d<e;d++)if(a[d]===b)return d;
|
16
|
+
return-1};c.lastIndexOf=function(a,b){if(z&&a.lastIndexOf===z)return a.lastIndexOf(b);for(var d=a.length;d--;)if(a[d]===b)return d;return-1};c.range=function(a,b,d){var e=i.call(arguments),f=e.length<=1;a=f?0:e[0];b=f?e[0]:e[1];d=e[2]||1;e=Math.max(Math.ceil((b-a)/d),0);f=0;for(var g=Array(e);f<e;){g[f++]=a;a+=d}return g};c.bind=function(a,b){var d=i.call(arguments,2);return function(){return a.apply(b||{},d.concat(i.call(arguments)))}};c.bindAll=function(a){var b=i.call(arguments,1);if(b.length==
|
17
|
+
0)b=c.functions(a);k(b,function(d){a[d]=c.bind(a[d],a)});return a};c.memoize=function(a,b){var d={};b=b||c.identity;return function(){var e=b.apply(this,arguments);return e in d?d[e]:d[e]=a.apply(this,arguments)}};c.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};c.defer=function(a){return c.delay.apply(c,[a,1].concat(i.call(arguments,1)))};var B=function(a,b,d){var e;return function(){var f=this,g=arguments,h=function(){e=null;a.apply(f,g)};d&&
|
18
|
+
clearTimeout(e);if(d||!e)e=setTimeout(h,b)}};c.throttle=function(a,b){return B(a,b,false)};c.debounce=function(a,b){return B(a,b,true)};c.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments));return b.apply(b,d)}};c.compose=function(){var a=i.call(arguments);return function(){for(var b=i.call(arguments),d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=F||function(a){if(c.isArray(a))return c.range(0,a.length);var b=[],d;for(d in a)if(q.call(a,d))b[b.length]=d;return b};
|
19
|
+
c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){k(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a.isEqual)return a.isEqual(b);
|
20
|
+
if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===
|
21
|
+
0;for(var b in a)if(q.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=n||function(a){return!!(a&&a.concat&&a.unshift&&!a.callee)};c.isArguments=function(a){return!!(a&&a.callee)};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return E.call(a)==="[object Number]"&&isNaN(a)};
|
22
|
+
c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){p._=C;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};c.mixin=function(a){k(c.functions(a),function(b){H(b,c[b]=a[b])})};var I=
|
23
|
+
0;c.uniqueId=function(a){var b=I++;return a?a+b:b};c.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,
|
24
|
+
"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},H=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);D.call(d,this._wrapped);return r(b.apply(c,d),this._chain)}};c.mixin(c);k(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=j[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);
|
25
|
+
return r(this._wrapped,this._chain)}});k(["concat","join","slice"],function(a){var b=j[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})();
|
@@ -0,0 +1,16 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title
|
5
|
+
LabBench Test Status
|
6
|
+
%link{ :href => css('app'), :rel => "stylesheet" }
|
7
|
+
%script{ :src => js('head.min') }
|
8
|
+
%body
|
9
|
+
%appstatus LabBench
|
10
|
+
%testruns
|
11
|
+
%eventlog
|
12
|
+
%script{ :type => "text/javascript" }
|
13
|
+
head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");
|
14
|
+
head.js("#{js('mustache')}");
|
15
|
+
head.js("#{js('underscore-min')}");
|
16
|
+
head.js("#{js('app')}");
|
data/bin/lab_bench_server
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'lab_bench'
|
5
5
|
|
6
|
+
require 'haml'
|
6
7
|
require 'eventmachine'
|
7
8
|
require 'em-websocket'
|
8
9
|
require 'sinatra/base'
|
@@ -10,22 +11,36 @@ require 'thin'
|
|
10
11
|
require 'yajl'
|
11
12
|
|
12
13
|
SOCKETS = []
|
14
|
+
MESSAGES = [] # TODO this is unbounded
|
13
15
|
|
14
16
|
class LabBenchServer < Sinatra::Base
|
15
17
|
set :public, LabBench::ASSETS
|
18
|
+
set :views, File.join(LabBench::ASSETS, 'views')
|
19
|
+
|
20
|
+
helpers do
|
21
|
+
def css(css)
|
22
|
+
"/css/#{css}.css?" + File.mtime(File.join(LabBench::ASSETS, "css", "#{css}.css")).to_i.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def js(js)
|
26
|
+
"/js/#{js}.js?" + File.mtime(File.join(LabBench::ASSETS, "js", "#{js}.js")).to_i.to_s
|
27
|
+
end
|
28
|
+
end
|
16
29
|
|
17
30
|
get '/' do
|
18
|
-
|
31
|
+
haml :index
|
19
32
|
end
|
20
33
|
|
21
|
-
# lets the
|
34
|
+
# lets the TestRunner ensure that we're up and running
|
22
35
|
get '/ping' do
|
23
36
|
'Pong!'
|
24
37
|
end
|
25
38
|
|
26
|
-
# give the
|
39
|
+
# give the TestRunner a chance to post events, which we cache and rebrooadcase
|
27
40
|
post '/test_event' do
|
28
41
|
message = Yajl::Encoder.encode(params.merge(:milliseconds => (Time.now.to_f * 1000).to_i))
|
42
|
+
MESSAGES << message
|
43
|
+
|
29
44
|
SOCKETS.each { |s| s.send message }
|
30
45
|
|
31
46
|
# should vend back a UID for this test run or something
|
@@ -38,6 +53,13 @@ EventMachine.run do
|
|
38
53
|
# HACK - websockets and HTTP on different (adjacent) ports
|
39
54
|
EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 9021) do |ws|
|
40
55
|
ws.onopen do
|
56
|
+
# backfill old messages to the client
|
57
|
+
# TODO is this blocking? I would guess no...
|
58
|
+
ws.send Yajl::Encoder.encode(['backfilling'])
|
59
|
+
MESSAGES.each { |message| ws.send(message) }
|
60
|
+
|
61
|
+
# put the client in the list of real-time recipients
|
62
|
+
ws.send Yajl::Encoder.encode(['realtime'])
|
41
63
|
SOCKETS << ws
|
42
64
|
end
|
43
65
|
|
@@ -45,7 +67,7 @@ EventMachine.run do
|
|
45
67
|
SOCKETS.delete(ws)
|
46
68
|
end
|
47
69
|
|
48
|
-
ws.onerror
|
70
|
+
ws.onerror { |e| puts "Error: #{e.message}" }
|
49
71
|
end
|
50
72
|
|
51
73
|
LabBenchServer.run!(:host => '0.0.0.0', :port => 9020)
|
data/lab_bench.gemspec
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{lab_bench}
|
8
|
+
s.version = "0.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Bradley Buda"]
|
12
|
+
s.date = %q{2010-12-03}
|
13
|
+
s.default_executable = %q{lab_bench_server}
|
14
|
+
s.description = %q{Like autotest, but in your browser. Currently unsuitable for use by anyone.}
|
15
|
+
s.email = %q{bradleybuda@gmail.com}
|
16
|
+
s.executables = ["lab_bench_server"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rvmrc",
|
24
|
+
"Gemfile",
|
25
|
+
"Gemfile.lock",
|
26
|
+
"LICENSE.txt",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"assets/css/app.css",
|
31
|
+
"assets/images/connect.png",
|
32
|
+
"assets/images/disconnect.png",
|
33
|
+
"assets/images/spinner.gif",
|
34
|
+
"assets/js/app.js",
|
35
|
+
"assets/js/head.min.js",
|
36
|
+
"assets/js/mustache.js",
|
37
|
+
"assets/js/underscore-min.js",
|
38
|
+
"assets/views/index.haml",
|
39
|
+
"bin/lab_bench_server",
|
40
|
+
"lab_bench.gemspec",
|
41
|
+
"lib/lab_bench.rb",
|
42
|
+
"lib/lab_bench/test_runner.rb",
|
43
|
+
"test/helper.rb",
|
44
|
+
"test/test_lab_bench.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/bradleybuda/lab_bench}
|
47
|
+
s.licenses = ["MIT"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.7}
|
50
|
+
s.summary = %q{A browser-based runner for Test::Unit}
|
51
|
+
s.test_files = [
|
52
|
+
"test/helper.rb",
|
53
|
+
"test/test_lab_bench.rb"
|
54
|
+
]
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
|
+
s.specification_version = 3
|
59
|
+
|
60
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
61
|
+
s.add_runtime_dependency(%q<haml>, ["~> 2.2.0"])
|
62
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 1.1.0"])
|
63
|
+
s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
64
|
+
s.add_runtime_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
65
|
+
s.add_runtime_dependency(%q<thin>, ["~> 1.2.0"])
|
66
|
+
s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
67
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
68
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
69
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
70
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
71
|
+
s.add_development_dependency(%q<hpricot>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<sinatra>, ["~> 1.1.0"])
|
73
|
+
s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
74
|
+
s.add_runtime_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
75
|
+
s.add_runtime_dependency(%q<thin>, ["~> 1.2.0"])
|
76
|
+
s.add_runtime_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<haml>, ["~> 2.2.0"])
|
79
|
+
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
80
|
+
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
81
|
+
s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
82
|
+
s.add_dependency(%q<thin>, ["~> 1.2.0"])
|
83
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
84
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
85
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
86
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
87
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<hpricot>, [">= 0"])
|
89
|
+
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
90
|
+
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
91
|
+
s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
92
|
+
s.add_dependency(%q<thin>, ["~> 1.2.0"])
|
93
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
94
|
+
end
|
95
|
+
else
|
96
|
+
s.add_dependency(%q<haml>, ["~> 2.2.0"])
|
97
|
+
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
98
|
+
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
99
|
+
s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
100
|
+
s.add_dependency(%q<thin>, ["~> 1.2.0"])
|
101
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
102
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
103
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
104
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
105
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
106
|
+
s.add_dependency(%q<hpricot>, [">= 0"])
|
107
|
+
s.add_dependency(%q<sinatra>, ["~> 1.1.0"])
|
108
|
+
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
109
|
+
s.add_dependency(%q<em-websocket>, ["~> 0.2.0"])
|
110
|
+
s.add_dependency(%q<thin>, ["~> 1.2.0"])
|
111
|
+
s.add_dependency(%q<yajl-ruby>, ["~> 0.7.8"])
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab_bench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bradley Buda
|
@@ -18,11 +18,107 @@ cert_chain: []
|
|
18
18
|
date: 2010-12-03 00:00:00 -08:00
|
19
19
|
default_executable: lab_bench_server
|
20
20
|
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
type: :runtime
|
24
|
+
name: haml
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 2
|
33
|
+
- 2
|
34
|
+
- 0
|
35
|
+
version: 2.2.0
|
36
|
+
requirement: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
prerelease: false
|
39
|
+
type: :runtime
|
40
|
+
name: sinatra
|
41
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 19
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 1
|
50
|
+
- 0
|
51
|
+
version: 1.1.0
|
52
|
+
requirement: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
prerelease: false
|
55
|
+
type: :runtime
|
56
|
+
name: eventmachine
|
57
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 59
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
- 12
|
66
|
+
- 10
|
67
|
+
version: 0.12.10
|
68
|
+
requirement: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
prerelease: false
|
71
|
+
type: :runtime
|
72
|
+
name: em-websocket
|
73
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 23
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
- 2
|
82
|
+
- 0
|
83
|
+
version: 0.2.0
|
84
|
+
requirement: *id004
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
prerelease: false
|
87
|
+
type: :runtime
|
88
|
+
name: thin
|
89
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 31
|
95
|
+
segments:
|
96
|
+
- 1
|
97
|
+
- 2
|
98
|
+
- 0
|
99
|
+
version: 1.2.0
|
100
|
+
requirement: *id005
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
prerelease: false
|
103
|
+
type: :runtime
|
104
|
+
name: yajl-ruby
|
105
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 19
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
- 7
|
114
|
+
- 8
|
115
|
+
version: 0.7.8
|
116
|
+
requirement: *id006
|
21
117
|
- !ruby/object:Gem::Dependency
|
22
118
|
prerelease: false
|
23
119
|
type: :development
|
24
120
|
name: shoulda
|
25
|
-
version_requirements: &
|
121
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
26
122
|
none: false
|
27
123
|
requirements:
|
28
124
|
- - ">="
|
@@ -31,12 +127,12 @@ dependencies:
|
|
31
127
|
segments:
|
32
128
|
- 0
|
33
129
|
version: "0"
|
34
|
-
requirement: *
|
130
|
+
requirement: *id007
|
35
131
|
- !ruby/object:Gem::Dependency
|
36
132
|
prerelease: false
|
37
133
|
type: :development
|
38
134
|
name: bundler
|
39
|
-
version_requirements: &
|
135
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
40
136
|
none: false
|
41
137
|
requirements:
|
42
138
|
- - ~>
|
@@ -47,12 +143,12 @@ dependencies:
|
|
47
143
|
- 0
|
48
144
|
- 0
|
49
145
|
version: 1.0.0
|
50
|
-
requirement: *
|
146
|
+
requirement: *id008
|
51
147
|
- !ruby/object:Gem::Dependency
|
52
148
|
prerelease: false
|
53
149
|
type: :development
|
54
150
|
name: jeweler
|
55
|
-
version_requirements: &
|
151
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
56
152
|
none: false
|
57
153
|
requirements:
|
58
154
|
- - ~>
|
@@ -63,12 +159,12 @@ dependencies:
|
|
63
159
|
- 5
|
64
160
|
- 1
|
65
161
|
version: 1.5.1
|
66
|
-
requirement: *
|
162
|
+
requirement: *id009
|
67
163
|
- !ruby/object:Gem::Dependency
|
68
164
|
prerelease: false
|
69
165
|
type: :development
|
70
166
|
name: rcov
|
71
|
-
version_requirements: &
|
167
|
+
version_requirements: &id010 !ruby/object:Gem::Requirement
|
72
168
|
none: false
|
73
169
|
requirements:
|
74
170
|
- - ">="
|
@@ -77,12 +173,26 @@ dependencies:
|
|
77
173
|
segments:
|
78
174
|
- 0
|
79
175
|
version: "0"
|
80
|
-
requirement: *
|
176
|
+
requirement: *id010
|
177
|
+
- !ruby/object:Gem::Dependency
|
178
|
+
prerelease: false
|
179
|
+
type: :development
|
180
|
+
name: hpricot
|
181
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
182
|
+
none: false
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
hash: 3
|
187
|
+
segments:
|
188
|
+
- 0
|
189
|
+
version: "0"
|
190
|
+
requirement: *id011
|
81
191
|
- !ruby/object:Gem::Dependency
|
82
192
|
prerelease: false
|
83
193
|
type: :runtime
|
84
194
|
name: sinatra
|
85
|
-
version_requirements: &
|
195
|
+
version_requirements: &id012 !ruby/object:Gem::Requirement
|
86
196
|
none: false
|
87
197
|
requirements:
|
88
198
|
- - ~>
|
@@ -93,12 +203,12 @@ dependencies:
|
|
93
203
|
- 1
|
94
204
|
- 0
|
95
205
|
version: 1.1.0
|
96
|
-
requirement: *
|
206
|
+
requirement: *id012
|
97
207
|
- !ruby/object:Gem::Dependency
|
98
208
|
prerelease: false
|
99
209
|
type: :runtime
|
100
210
|
name: eventmachine
|
101
|
-
version_requirements: &
|
211
|
+
version_requirements: &id013 !ruby/object:Gem::Requirement
|
102
212
|
none: false
|
103
213
|
requirements:
|
104
214
|
- - ~>
|
@@ -109,12 +219,12 @@ dependencies:
|
|
109
219
|
- 12
|
110
220
|
- 10
|
111
221
|
version: 0.12.10
|
112
|
-
requirement: *
|
222
|
+
requirement: *id013
|
113
223
|
- !ruby/object:Gem::Dependency
|
114
224
|
prerelease: false
|
115
225
|
type: :runtime
|
116
226
|
name: em-websocket
|
117
|
-
version_requirements: &
|
227
|
+
version_requirements: &id014 !ruby/object:Gem::Requirement
|
118
228
|
none: false
|
119
229
|
requirements:
|
120
230
|
- - ~>
|
@@ -125,12 +235,12 @@ dependencies:
|
|
125
235
|
- 2
|
126
236
|
- 0
|
127
237
|
version: 0.2.0
|
128
|
-
requirement: *
|
238
|
+
requirement: *id014
|
129
239
|
- !ruby/object:Gem::Dependency
|
130
240
|
prerelease: false
|
131
241
|
type: :runtime
|
132
242
|
name: thin
|
133
|
-
version_requirements: &
|
243
|
+
version_requirements: &id015 !ruby/object:Gem::Requirement
|
134
244
|
none: false
|
135
245
|
requirements:
|
136
246
|
- - ~>
|
@@ -141,12 +251,12 @@ dependencies:
|
|
141
251
|
- 2
|
142
252
|
- 0
|
143
253
|
version: 1.2.0
|
144
|
-
requirement: *
|
254
|
+
requirement: *id015
|
145
255
|
- !ruby/object:Gem::Dependency
|
146
256
|
prerelease: false
|
147
257
|
type: :runtime
|
148
258
|
name: yajl-ruby
|
149
|
-
version_requirements: &
|
259
|
+
version_requirements: &id016 !ruby/object:Gem::Requirement
|
150
260
|
none: false
|
151
261
|
requirements:
|
152
262
|
- - ~>
|
@@ -157,7 +267,7 @@ dependencies:
|
|
157
267
|
- 7
|
158
268
|
- 8
|
159
269
|
version: 0.7.8
|
160
|
-
requirement: *
|
270
|
+
requirement: *id016
|
161
271
|
description: Like autotest, but in your browser. Currently unsuitable for use by anyone.
|
162
272
|
email: bradleybuda@gmail.com
|
163
273
|
executables:
|
@@ -177,12 +287,16 @@ files:
|
|
177
287
|
- Rakefile
|
178
288
|
- VERSION
|
179
289
|
- assets/css/app.css
|
290
|
+
- assets/images/connect.png
|
291
|
+
- assets/images/disconnect.png
|
180
292
|
- assets/images/spinner.gif
|
181
|
-
- assets/index.html
|
182
293
|
- assets/js/app.js
|
183
294
|
- assets/js/head.min.js
|
184
295
|
- assets/js/mustache.js
|
296
|
+
- assets/js/underscore-min.js
|
297
|
+
- assets/views/index.haml
|
185
298
|
- bin/lab_bench_server
|
299
|
+
- lab_bench.gemspec
|
186
300
|
- lib/lab_bench.rb
|
187
301
|
- lib/lab_bench/test_runner.rb
|
188
302
|
- test/helper.rb
|
data/assets/index.html
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
<!DOCTYPE HTML>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>LabBench Test Status</title>
|
5
|
-
<link rel="stylesheet" href="/css/app.css">
|
6
|
-
<script src="/js/head.min.js"></script>
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<testruns></testruns>
|
10
|
-
<eventlog></eventlog>
|
11
|
-
|
12
|
-
<script type='text/javascript'>
|
13
|
-
head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js");
|
14
|
-
head.js("/js/mustache.js");
|
15
|
-
head.js("/js/app.js");
|
16
|
-
</script>
|
17
|
-
</body>
|
18
|
-
</html>
|